Hide 捉迷藏
Description
Jiajia和Wind是一对恩爱的夫妻,并且他们有很多孩子。某天,Jiajia、Wind和孩子们决定在家里玩捉迷藏游戏。他们的家很大且构造很奇特,由N个屋子和N-1条双向走廊组成,这N-1条走廊的分布使得任意两个屋子都互相可达。
游戏是这样进行的,孩子们负责躲藏,Jiajia负责找,而Wind负责操纵这N个屋子的灯。在起初的时候,所有的灯都没有被打开。每一次,孩子们只会躲藏在没有开灯的房间中,但是为了增加刺激性,孩子们会要求打开某个房间的电灯或者关闭某个房间的电灯。为了评估某一次游戏的复杂性,Jiajia希望知道可能的最远的两个孩子的距离(即最远的两个关灯房间的距离)。
我们将以如下形式定义每一种操作: C(hange) i 改变第i个房间的照明状态,若原来打开,则关闭;若原来关闭,则打开。 G(ame) 开始一次游戏,查询最远的两个关灯房间的距离。
Input
第一行包含一个整数N,表示房间的个数,房间将被编号为1,2,3…N的整数。
接下来N-1行每行两个整数a, b,表示房间a与房间b之间有一条走廊相连。接下来一行包含一个整数Q,表示操作次数。接着Q行,每行一个操作,如上文所示。
Output
对于每一个操作Game,输出一个非负整数到hide.out,表示最远的两个关灯房间的距离。若只有一个房间是关着灯的,输出0;若所有房间的灯都开着,输出-1。
Sample Input
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
Sample Output
4
3
3
4
HINT
对于100%的数据, N ≤100000, M ≤500000。
两天。
没有什么能比这两个字更能表达出本文作者濒临崩溃的状态。
要不是网上的题解救命估计作者现在还无法成功找出某奇怪的细节错误。
思路:
考虑没有修改的情况。
那么这就是个裸树分治.jpg
考虑有修改的情况。
那么考虑动态维护答案。
对于每个分治重心,要找出到达分治重心的最长链和次长链。
现在,考虑对每个分治节点建两个堆q1和q2,再维护一个全局堆ans。
假想把所有的分治中心连起来建成一棵树,就叫它分治树吧。
那么q1维护的就是当前分治节点在分治树上的父亲,从指向当前点的那个儿子开始所有有效节点的相对深度。
接着q2维护当前节点在分治树上子节点中所有q1的堆顶。
同时,考虑全局一个堆维护每个节点的q2的堆顶的前两个元素的和,也就是在每个q2处能取到的最长的链的值。
那么全局堆的堆顶就是答案了。
考虑动态维护答案,那么考虑一个节点的加入和删除将会修改哪个堆内元素。
q1显然无需多言,把被修改的节点到当前分治节点的距离从堆中加入删除即可。
q2的话,把堆顶删掉,修改q1,然后再从q1处取回新堆顶即可。
全局堆ans同q2,先删掉当前q2堆顶的值,修改完q2后再重新加回即可。
那么这就结束了~
关于堆的删除:
只需要再开一个删除标记堆存被删除的值,访问时若删除标记堆顶和原堆顶的值相同则同时pop掉并跳过即可。
#include<iostream>
#include<queue>
#include<cmath>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
using namespace std;
const int N=100009;
const int K=21;
inline int read()
{
int x=0;char ch=getchar();
while(ch<'0' || '9'<ch)ch=getchar();
while('0'<=ch && ch<='9')x=x*10+(ch^48),ch=getchar();
return x;
}
inline int minn(int a,int b){if(a<b)return a;return b;}
inline void chkmax(int &a,int b){if(a<b)a=b;}
struct Priority_queue
{
priority_queue<int> q,del;
inline void push(int x){q.push(x);}
inline void deletes(int x){del.push(x);}
inline void update()
{
while(del.size() && q.top()==del.top())
q.pop(),del.pop();
}
inline void pop()
{
update();
q.pop();
}
inline int top()
{
update();
return q.top();
}
inline int second_top()
{
int tmp=top();pop();
int ret=top();push(tmp);
return ret;
}
inline int size()
{
return q.size()-del.size();
}
}q1[N],q2[N],ans;
int n,m,rest;
int to[N<<1],nxt[N<<1],beg[N],tot=1;
int fa[N],st[N<<1][K],logs[N<<1],dep[N],id[N],dfn;
bool ban[N<<1],state[N];
inline void add(int u,int v)
{
to[++tot]=v;
nxt[tot]=beg[u];
beg[u]=tot;
}
inline int get_siz(int u,int fat)
{
int ret=1;
for(int i=beg[u],v;i;i=nxt[i])
if(!ban[i] && (v=to[i])!=fat)
ret+=get_siz(v,u);
return ret;
}
inline void build(int u,int fat,int dep,Priority_queue &q)
{
q.push(dep);
for(int i=beg[u],v;i;i=nxt[i])
if(!ban[i] && (v=to[i])!=fat)
build(v,u,dep+1,q);
}
inline int get_center(int u,int fat,int totsiz,int ¢er)
{
int ret=1,mx=0;
for(int i=beg[u],v,tmp;i;i=nxt[i])
if(!ban[i] && (v=to[i])!=fat)
{
ret+=(tmp=get_center(v,u,totsiz,center));
chkmax(mx,tmp);
}
chkmax(mx,totsiz-ret);
if((mx<<1)<=totsiz)
center=u;
return ret;
}
inline void push(Priority_queue &q)
{
if(q.size()>=2)
ans.push(q.top()+q.second_top());
}
inline void deletes(Priority_queue &q)
{
if(q.size()>=2)
ans.deletes(q.top()+q.second_top());
}
inline int solve(int u)
{
int siz=get_siz(u,0),center;
get_center(u,0,siz,center);
q2[center].push(0);
for(int i=beg[center],v;i;i=nxt[i])
if(!ban[i])
{
ban[i]=ban[i^1]=1;
Priority_queue q;
build(v=to[i],0,1,q);
int son=solve(v);
fa[son]=center;
q1[son]=q;
q2[center].push(q1[son].top());
}
push(q2[center]);
return center;
}
inline void dfs(int u,int fat)
{
st[id[u]=++dfn][0]=dep[u]=dep[fat]+1;
for(int i=beg[u],v;i;i=nxt[i])
if((v=to[i])!=fat)
{
dfs(v,u);
st[++dfn][0]=dep[u];
}
}
inline void init()
{
for(int i=2;i<=dfn;i++)
logs[i]=logs[i>>1]+1;
for(int i=1;i<=logs[dfn];i++)
for(int j=1;j+(1<<i)-1<=dfn;j++)
st[j][i]=minn(st[j][i-1],st[j+(1<<i-1)][i-1]);
}
inline int dist(int u,int v)
{
int ret=dep[u]+dep[v];
u=id[u],v=id[v];
if(u>v)swap(u,v);
int dis=logs[v-u+1];
return ret-2*minn(st[u][dis],st[v-(1<<dis)+1][dis]);
}
inline void on(int x)
{
deletes(q2[x]);
q2[x].push(0);
push(q2[x]);
for(int i=x;fa[i];i=fa[i])
{
deletes(q2[fa[i]]);
if(q1[i].size())
q2[fa[i]].deletes(q1[i].top());
q1[i].push(dist(fa[i],x));
if(q1[i].size())
q2[fa[i]].push(q1[i].top());
push(q2[fa[i]]);
}
}
inline void off(int x)
{
deletes(q2[x]);
q2[x].deletes(0);
push(q2[x]);
for(int i=x;fa[i];i=fa[i])
{
deletes(q2[fa[i]]);
if(q1[i].size())
q2[fa[i]].deletes(q1[i].top());
q1[i].deletes(dist(fa[i],x));
if(q1[i].size())
q2[fa[i]].push(q1[i].top());
push(q2[fa[i]]);
}
}
int main()
{
rest=n=read();
for(int i=1,u,v;i<n;i++)
{
u=read();v=read();
add(u,v);add(v,u);
}
solve(1);
dfs(1,0);
init();
for(int i=1;i<=n;i++)
state[i]=1;
m=read();
char s[10];
for(int i=1;i<=m;i++)
{
scanf("%s",s+1);
if(s[1]=='G')
{
if(rest<=1)
printf("%d\n",rest-1);
else
printf("%d\n",ans.top());
}
else
{
int x=read();
if(state[x]==1)
{
rest--;
state[x]=0;
off(x);
}
else
{
rest++;
state[x]=1;
on(x);
}
}
}
return 0;
}