1095: [ZJOI2007]Hide 捉迷藏
Time Limit: 40 Sec Memory Limit: 256 MBSubmit: 4330 Solved: 1818
[Submit][Status][Discuss]
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
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
3
3
4
HINT
对于100%的数据, N ≤100000, M ≤500000。
Source
以前看到这个算法就觉得好高深,所以一直没学。现在看来这个算法怎么这么逗啊!
先构造出点分树,然后每个节点开两个堆分别维护子树到他的所有链和他的子树到父分治节点的所有链。
再开一个全局堆维护每个节点的最大答案。
1 #include<iostream> 2 #include<cstring> 3 #include<cstdio> 4 #include<cstdlib> 5 #include<cmath> 6 #include<algorithm> 7 #include<queue> 8 using namespace std; 9 #define maxn 100005 10 int read() { 11 int x=0,f=1;char ch=getchar(); 12 for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-1; 13 for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0'; 14 return x*f; 15 } 16 struct edge { 17 int to,next; 18 }e[maxn*2]; 19 int head[maxn],cnt; 20 void add(int u,int v) {e[cnt].to=v;e[cnt].next=head[u];head[u]=cnt++;} 21 struct data { 22 priority_queue<int> q,del; 23 void push(int x) {q.push(x);} 24 void erase(int x) {del.push(x);} 25 int top() {while(del.size()&&del.top()==q.top()) {del.pop();q.pop();}return q.top();} 26 void pop() {while(del.size()&&del.top()==q.top()){del.pop();q.pop();}q.pop();} 27 int sectop() {int tmp=top();pop();int re=top();push(tmp);return re;} 28 int size() {return q.size()-del.size();} 29 }c[maxn],f[maxn],ans; 30 void insert(data &s) {if(s.size()>1) ans.push(s.top()+s.sectop());} 31 void dele(data &s) {if(s.size()>1) ans.erase(s.top()+s.sectop());} 32 int n; 33 int light[maxn],vis[maxn],fa[maxn],up[maxn][25],dep[maxn]; 34 void dfs(int x,int ff) { 35 up[x][0]=ff; 36 for(int i=1;i<=20;i++) up[x][i]=up[up[x][i-1]][i-1]; 37 for(int i=head[x];i>=0;i=e[i].next) { 38 int to=e[i].to;if(to==ff) continue; 39 dep[to]=dep[x]+1; 40 dfs(to,x); 41 } 42 } 43 int findlca(int x,int y) { 44 if(dep[x]<dep[y]) swap(x,y); 45 int t=dep[x]-dep[y]; 46 for(int i=20;i>=0;i--) if(t&(1<<i)) x=up[x][i]; 47 for(int i=20;i>=0;i--) if(up[x][i]!=up[y][i]) x=up[x][i],y=up[y][i]; 48 return x==y?x:up[x][0]; 49 } 50 int root,sum,fs[maxn],son[maxn]; 51 void findroot(int x,int ff) { 52 son[x]=1;fs[x]=0; 53 for(int i=head[x];i>=0;i=e[i].next) { 54 int to=e[i].to;if(vis[to]||to==ff) continue; 55 findroot(to,x); 56 son[x]+=son[to]; 57 fs[x]=max(fs[x],son[to]); 58 } 59 fs[x]=max(fs[x],sum-son[x]); 60 if(fs[x]<fs[root]) root=x; 61 } 62 void work(int x,int ff,int rt) { 63 f[root].push(dep[x]+dep[rt]-2*dep[findlca(x,rt)]); 64 // cout<<x<<' '<<rt<<' '<<root<<' '<<dep[x]+dep[rt]-2*dep[findlca(x,rt)]<<endl; 65 for(int i=head[x];i>=0;i=e[i].next) { 66 int to=e[i].to;if(to==ff||vis[to]) continue; 67 work(to,x,rt); 68 } 69 } 70 void build_tree(int x,int ff) { 71 //cout<<x<<' '<<ff<<':'<<endl; 72 fa[x]=ff;vis[x]=1; 73 c[x].push(0); 74 work(x,0,ff); 75 for(int i=head[x];i>=0;i=e[i].next) { 76 int to=e[i].to;if(vis[to]) continue; 77 root=0;fs[0]=214748364;sum=son[to];findroot(to,x); 78 to=root; 79 build_tree(root,x); 80 c[x].push(f[to].top()); 81 } 82 insert(c[x]); 83 } 84 void ton(int x) { 85 dele(c[x]); 86 c[x].erase(0); 87 insert(c[x]); 88 for(int i=x;i;i=fa[i]) { 89 dele(c[fa[i]]); 90 if(f[i].size()) c[fa[i]].erase(f[i].top()); 91 f[i].erase(dep[x]+dep[fa[i]]-2*dep[findlca(x,fa[i])]); 92 if(f[i].size()) c[fa[i]].push(f[i].top()); 93 insert(c[fa[i]]); 94 } 95 } 96 void toff(int x) { 97 dele(c[x]); 98 c[x].push(0); 99 insert(c[x]); 100 for(int i=x;i;i=fa[i]) { 101 dele(c[fa[i]]); 102 if(f[i].size()) c[fa[i]].erase(f[i].top()); 103 f[i].push(dep[x]+dep[fa[i]]-2*dep[findlca(x,fa[i])]); 104 if(f[i].size()) c[fa[i]].push(f[i].top()); 105 insert(c[fa[i]]); 106 } 107 } 108 int main() { 109 //freopen("hide0.in","r",stdin); 110 memset(head,-1,sizeof(head)); 111 n=read(); 112 for(int i=1;i<n;i++) { 113 int x=read(),y=read(); 114 add(x,y);add(y,x); 115 } 116 dfs(1,0); 117 fs[0]=214748364;root=0;sum=n;findroot(1,0); 118 build_tree(root,0); 119 int num=n; 120 int q=read(); 121 while(q--) { 122 char ch[10];int x; 123 scanf("%s",ch); 124 if(ch[0]=='C') { 125 x=read(); 126 if(light[x]) {toff(x);num++;light[x]=0;} 127 else {ton(x);num--;light[x]=1;} 128 } 129 else { 130 if(num<=1) printf("%d\n",num-1); 131 else printf("%d\n",ans.top()); 132 } 133 } 134 }