P2056 [ZJOI2007] 捉迷藏 题解

P2056 [ZJOI2007] 捉迷藏

题面:

题目描述

Jiajia 和 Wind 是一对恩爱的夫妻,并且他们有很多孩子。某天,Jiajia、Wind 和孩子们决定在家里玩捉迷藏游戏。他们的家很大且构造很奇特,由 N N N 个屋子和 N − 1 N-1 N−1 条双向走廊组成,这 N − 1 N-1 N−1 条走廊的分布使得任意两个屋子都互相可达。

游戏是这样进行的,孩子们负责躲藏,Jiajia 负责找,而 Wind 负责操纵这 N N N 个屋子的灯。在起初的时候,所有的灯都没有被打开。每一次,孩子们只会躲藏在没有开灯的房间中,但是为了增加刺激性,孩子们会要求打开某个房间的电灯或者关闭某个房间的电灯。为了评估某一次游戏的复杂性,Jiajia 希望知道可能的最远的两个孩子的距离(即最远的两个关灯房间的距离)。

我们将以如下形式定义每一种操作:

  • C(hange) i 改变第 i i i 个房间的照明状态,若原来打开,则关闭;若原来关闭,则打开。
  • G(ame) 开始一次游戏,查询最远的两个关灯房间的距离。
输入格式

第一行包含一个整数 N N N,表示房间的个数,房间将被编号为 1 , 2 , 3 ... N 1,2,3...N 1,2,3...N 的整数。

接下来 N − 1 N-1 N−1 行每行两个整数 a a a, b b b,表示房间 a a a 与房间 b b b 之间有一条走廊相连。

接下来一行包含一个整数 Q Q Q,表示操作次数。接着 Q Q Q 行,每行一个操作,如上文所示。

输出格式

对于每一个操作 Game,输出一个非负整数,表示最远的两个关灯房间的距离。若只有一个房间是关着灯的,输出 0;若所有房间的灯都开着,输出 -1

样例 #1
样例输入 #1
8
1 2
2 3
3 4
3 5
3 6
6 7
6 8
7
G
C 1
G
C 2
G
C 1
G
样例输出 #1
4
3
3
4
提示

对于 20 % 20\% 20%的数据, N ≤ 50 N \leq 50 N≤50, M ≤ 100 M\leq 100 M≤100;

对于 60 % 60\% 60%的数据, N ≤ 3000 N \leq 3000 N≤3000, M ≤ 10000 M \leq 10000 M≤10000;

对于 100 % 100\% 100%的数据, N ≤ 100000 N \leq 100000 N≤100000, M ≤ 500000 M \leq 500000 M≤500000。

出现 & 消失!

太棒了,线段树分治!

我们建立时间线段树,将每个点的出现到消失时间插入线段树里面。

然后是结论时间!

结论:当树中新加入一个节点 x x x,原先的 u ⇝ v u \leadsto v u⇝v 直径,只会变成 u ⇝ x u \leadsto x u⇝x 或 x ⇝ v x \leadsto v x⇝v

证明:若插入一个 x x x,如果原直径是 u ⇝ v u\leadsto v u⇝v,而新直径是 x ⇝ y x\leadsto y x⇝y,则 u ⇝ y u \leadsto y u⇝y 或 v ⇝ y v\leadsto y v⇝y 肯定比 u ⇝ v u\leadsto v u⇝v 更长,故矛盾!

那么我们要在栈中记录 u , v u,v u,v,然后通过上面的结论,更新 u , v u,v u,v,退出线段树节点时撤回退栈。

然后对每个时间点,记录答案。

求两点距离,考虑树剖 + 树上差分。

AC-code:

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define pii pair<int,int>
int rd() {
	int x = 0, w = 1;
	char ch = 0;
	while (ch < '0' || ch > '9') {
		if (ch == '-') w = -1;
		ch = getchar();
	}
	while (ch >= '0' && ch <= '9') {
		x = x * 10 + (ch - '0');
		ch = getchar();
	}
	return x * w;
}
void wt(int x) {
	static int sta[35];
	int f = 1;
	if(x < 0) f = -1,x *= f;
	int top = 0;
	do {
		sta[top++] = x % 10, x /= 10;
	} while (x);
	if(f == -1) putchar('-');
	while (top) putchar(sta[--top] + 48);
}
const int N = 5e5+5;
int head[N],nxt[N<<1],to[N<<1],cnt;
void init() {memset(head,-1,sizeof(head));cnt = 0;}
void add(int u,int v) {
    nxt[cnt] = head[u];
    to[cnt] = v;
    head[u] = cnt++;
}
int lst[N],n,q;
int fa[N],siz[N],top[N],son[N],dep[N];
void dfs1(int x,int f) {
    fa[x] = f;
    siz[x] = 1;
    dep[x] = dep[f] + 1;
    for(int i = head[x];~i;i = nxt[i]) {
        int y = to[i];
        if(y ^ f) {
            dfs1(y,x);
            siz[x] += siz[y];
            if(siz[son[x]] < siz[y]) son[x] = y;
        }
    }
}
void dfs2(int x,int topx) {
    top[x] = topx;
    if(!son[x]) return;
    dfs2(son[x],topx);
    for(int i = head[x];~i;i = nxt[i]) {
        int y = to[i];
        if(y ^ fa[x] && y ^ son[x]) 
            dfs2(y,y);
    }
}
int lca(int x,int y) {
    while(top[x] ^ top[y]) {
        if(dep[top[x]] < dep[top[y]]) swap(x,y);
        x = fa[top[x]];
    }
    return dep[x] < dep[y] ? x : y;
}
bitset<N> col,qb;
vector<int> t[N<<2];
stack<pii> st;
int u,v,ans[N];
int dis(int x,int y) {
    return dep[x] + dep[y] - 2 * dep[lca(x,y)];
}
#define mid ((pl + pr) >> 1)
#define ls (p << 1)
#define rs (ls | 1)
void insert(int p,int pl,int pr,int l,int r,int x) {
    if(l <= pl && pr <= r) {t[p].emplace_back(x);return;}
    if(l <= mid) insert(ls,pl,mid,l,r,x);
    if(r > mid) insert(rs,mid+1,pr,l,r,x);
}
void solve(int p,int pl,int pr) {
    auto now = st.size();
    for(int x : t[p]) {
        st.push({u,v});
        if(!u && !v) u = v = x;
        else {
            int d0 = dis(u,v),d1 = dis(u,x),d2 = dis(v,x);
            int d = max(d0,max(d1,d2));
            if(d == d1) v = x;
            else if(d == d2) u = x;
        }
    }
    if(pl == pr) ans[pl] = (!u || !v) ? -1 : dis(u,v);
    else solve(ls,pl,mid),solve(rs,mid+1,pr);
    while(st.size() != now) {
        auto t = st.top();
        u = t.first,v = t.second;
        st.pop();
    }
}

signed main() {
    init();
    n = rd();
    for(int i = 1;i<n;i++) {
        int u = rd(),v = rd();
        add(u,v);add(v,u);
    }
    q = rd();
    dfs1(1,0);dfs2(1,1);
    for(int i = 1;i<=n;i++) lst[i] = 1; 
    for(int i = 1;i<=q;i++) {
        char op = getchar();
        while(op != 'C' && op != 'G') op = getchar();
        if(op == 'C') {
            int s = rd();
            if(!col[s]) {
                col[s] = 1;
                insert(1,1,q,lst[s],i,s);
            }else col[s] = 0,lst[s] = i;
        }else qb[i] = 1;
    }
    for(int i = 1;i<=n;i++) 
        if(!col[i]) 
            insert(1,1,q,lst[i],q,i);
    solve(1,1,q);
    for(int i = 1;i<=q;i++)
        if(qb[i])
            wt(ans[i]),putchar('\n');
	return 0;
}
相关推荐
‘’林花谢了春红‘’12 分钟前
C++ list (链表)容器
c++·链表·list
----云烟----36 分钟前
QT中QString类的各种使用
开发语言·qt
lsx20240641 分钟前
SQL SELECT 语句:基础与进阶应用
开发语言
开心工作室_kaic1 小时前
ssm161基于web的资源共享平台的共享与开发+jsp(论文+源码)_kaic
java·开发语言·前端
向宇it1 小时前
【unity小技巧】unity 什么是反射?反射的作用?反射的使用场景?反射的缺点?常用的反射操作?反射常见示例
开发语言·游戏·unity·c#·游戏引擎
武子康1 小时前
Java-06 深入浅出 MyBatis - 一对一模型 SqlMapConfig 与 Mapper 详细讲解测试
java·开发语言·数据仓库·sql·mybatis·springboot·springcloud
转世成为计算机大神2 小时前
易考八股文之Java中的设计模式?
java·开发语言·设计模式
机器视觉知识推荐、就业指导2 小时前
C++设计模式:建造者模式(Builder) 房屋建造案例
c++
宅小海2 小时前
scala String
大数据·开发语言·scala
qq_327342732 小时前
Java实现离线身份证号码OCR识别
java·开发语言