BZOJ1095: [ZJOI2007]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
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
3
3
4
HINT
对于100%的数据, N ≤100000, M ≤500000。
妈妈我终于写完动态树分治了。
code几乎抄了一遍黄学长的。
看这篇吧:http://hzwer.com/5247.html
#include<cstdio> #include<cctype> #include<queue> #include<cstring> #include<algorithm> #define rep(s,t) for(int i=s;i<=t;i++) #define ren for(int i=first[x];i;i=next[i]) using namespace std; inline int read() { int x=0,f=1;char c=getchar(); for(;!isdigit(c);c=getchar()) if(c=='-') f=-1; for(;isdigit(c);c=getchar()) x=x*10+c-'0'; return x*f; } const int maxn=200010; struct Heap { priority_queue<int> A,del; void push(int x) {A.push(x);} void erase(int x) {del.push(x);} void pop() { while(del.size()&&A.top()==del.top()) A.pop(),del.pop(); A.pop(); } int top() { while(del.size()&&A.top()==del.top()) A.pop(),del.pop(); return !A.size()?0:A.top(); } int size() {return A.size()-del.size();} int stop() { if(size()<2) return 0; int t1=top();pop(); int t2=top();push(t1); return t2; } }A,B[maxn],C[maxn]; int n,m,clo[maxn],first[maxn],next[maxn],to[maxn],es; void AddEdge(int u,int v) { to[++es]=v;next[es]=first[u];first[u]=es; to[++es]=u;next[es]=first[v];first[v]=es; } int Log[maxn],mn[19][maxn],dep[maxn],pos[maxn],dfs_clock; void dfs(int x,int fa) { mn[0][++dfs_clock]=dep[x];pos[x]=dfs_clock; ren if(to[i]!=fa) { dep[to[i]]=dep[x]+1; dfs(to[i],x); mn[0][++dfs_clock]=dep[x]; } } void init() { Log[0]=-1;rep(1,200000) Log[i]=Log[i>>1]+1; for(int i=1;(1<<i)<=dfs_clock;i++) for(int j=1;j+(1<<i)-1<=dfs_clock;j++) mn[i][j]=min(mn[i-1][j],mn[i-1][j+(1<<(i-1))]); } int dist(int x,int y) { int ans=dep[x]+dep[y]; x=pos[x];y=pos[y];if(x>y) swap(x,y); int k=Log[y-x+1]; return ans-2*min(mn[k][x],mn[k][y-(1<<k)+1]); } int root,size,vis[maxn],f[maxn],s[maxn]; void getroot(int x,int fa) { int maxs=0;s[x]=1; ren if(to[i]!=fa&&!vis[to[i]]) getroot(to[i],x),maxs=max(maxs,s[to[i]]),s[x]+=s[to[i]]; f[x]=max(maxs,size-s[x]); if(f[root]>f[x]) root=x; } int fa[maxn]; void solve(int x,int F) { fa[x]=F;vis[x]=1; ren if(!vis[to[i]]) { size=f[0]=s[to[i]];getroot(to[i],root=0); solve(root,x); } } void turn_off(int u,int v) { if(u==v) { B[u].push(0); if(B[u].size()==2) A.push(B[u].top()); } if(!fa[u]) return; int f=fa[u],D=dist(f,v),tmp=C[u].top();C[u].push(D); if(D>tmp) { int mx=B[f].top()+B[f].stop(),size=B[f].size(); if(tmp) B[f].erase(tmp); B[f].push(D); int now=B[f].top()+B[f].stop(); if(now>mx) { if(size>=2) A.erase(mx); if(B[f].size()>=2) A.push(now); } } turn_off(f,v); } void turn_on(int u,int v) { if(u==v) { if(B[u].size()==2) A.erase(B[u].top()); B[u].erase(0); } if(!fa[u]) return; int f=fa[u],D=dist(f,v),tmp=C[u].top(); C[u].erase(D); if(D==tmp) { int mx=B[f].top()+B[f].stop(),size=B[f].size(); B[f].erase(D); if(C[u].top()) B[f].push(C[u].top()); int now=B[f].top()+B[f].stop(); if(now<mx) { if(size>=2) A.erase(mx); if(B[f].size()>=2) A.push(now); } } turn_on(f,v); } int main() { n=read(); rep(2,n) AddEdge(read(),read()); dfs(1,0);init(); size=f[0]=n;getroot(1,root=0); solve(root,0); rep(1,n) clo[i]=1,C[i].push(0),turn_off(i,i); char ch[2]; m=read();int cnt=n; while(m--) { scanf("%s",ch); if(ch[0]=='G') printf("%d\n",cnt<2?-1:A.top()); else { int x=read(); if(clo[x]) turn_on(x,x),cnt--; else turn_off(x,x),cnt++; clo[x]^=1; } } return 0; }