[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

Sample Output

4
3
3
4

HINT

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

动态点分治

它的主要思想就是通过将的重心相连来维护一棵“点分树”,通过“点分树”中各个节点与其儿子间的联系来实现在线修改和查询的目的。

这样修改一个点只要顺着父亲跳并更新,显然点分树深度不超过logn

经过一个点的答案显然是一个子树最远的黑点+另一个子树最远的黑点

可以令q1[x]堆表示点到x的上一个根的距离

这样q2[pa]堆维护pa的子树中的最大距离,q2[pa].push(q1[x].top())

q3堆表示答案,用q2[x]中的最大值和次大值和插入

不过q2[x]要插入0,以免出现路径没有超过x的情况没有统计

修改的话:开灯操作就是把q2[x]堆中的0删掉,因为路径不能在x停下

然后从下往上更新,把q1[i]堆中与x到fa[i]的距离删掉

每一步都要重新计算q2,q3

关灯同理,加入0,把距离加入

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cstring>
  4 #include<cmath>
  5 #include<algorithm>
  6 #include<queue>
  7 using namespace std;
  8 const int N=100000;
  9 struct Node
 10 {
 11   int next,to;
 12 }edge[2*N+5];
 13 int head[N+5],num,fa[N+5][21],dep[N+5],size[N+5],maxsize[N+5],minsize,root,FA[N+5],n,m,cnt;
 14 int light[N+5];
 15 char ch[41];
 16 bool vis[N+5];
 17 struct Heap
 18 {
 19   priority_queue<int>q,p;
 20   void push(int x)
 21   {q.push(x);}
 22   void erase(int x)
 23   {p.push(x);}
 24   int top()
 25   {
 26     while (!q.empty()&&!p.empty()&&q.top()==p.top()) q.pop(),p.pop();
 27     return q.top();
 28   }
 29   int sec()
 30   {
 31     while (!q.empty()&&!p.empty()&&q.top()==p.top()) q.pop(),p.pop();
 32     int tmp=q.top();q.pop();
 33     while (!q.empty()&&!p.empty()&&q.top()==p.top()) q.pop(),p.pop();
 34     int val=q.top();
 35     q.push(tmp);
 36     return val;
 37   }
 38   int size()
 39   {
 40     return q.size()-p.size();
 41   }
 42 }q1[100001],q2[100001],q3;
 43 void add(int u,int v)
 44 {
 45   num++;
 46   edge[num].next=head[u];
 47   head[u]=num;
 48   edge[num].to=v;
 49 }
 50 void dfs(int x,int pa)
 51 {int i;
 52   fa[x][0]=pa;
 53   dep[x]=dep[pa]+1;
 54   for (i=head[x];i;i=edge[i].next)
 55     {
 56       int v=edge[i].to;
 57       if (v==pa) continue;
 58       dfs(v,x);
 59     }
 60 }
 61 int lca(int x,int y)
 62 {int i;
 63   if (dep[x]<dep[y]) swap(x,y);
 64   for (i=20;i>=0;i--)
 65     if (dep[x]-(1<<i)>=dep[y]) x=fa[x][i];
 66   if (x==y) return x;
 67   for (i=20;i>=0;i--)
 68     if (fa[x][i]!=fa[y][i])
 69       {
 70     x=fa[x][i];
 71     y=fa[y][i];
 72       }
 73   return fa[x][0];
 74 }
 75 void get_size(int x,int pa)
 76 {int i;
 77   size[x]=1;
 78   maxsize[x]=0;
 79   for (i=head[x];i;i=edge[i].next)
 80     {
 81       int v=edge[i].to;
 82       if (vis[v]||v==pa) continue;
 83       get_size(v,x);
 84       size[x]+=size[v];
 85       if (maxsize[x]<size[v]) maxsize[x]=size[v]; 
 86     }
 87 }
 88 void get_root(int x,int r,int pa)
 89 {int i;
 90   maxsize[x]=max(maxsize[x],size[r]-size[x]);
 91   if (minsize>maxsize[x])
 92     {
 93       minsize=maxsize[x];
 94       root=x;
 95     }
 96   for (i=head[x];i;i=edge[i].next)
 97     {
 98       int v=edge[i].to;
 99       if (v==pa||vis[v]) continue;
100       get_root(v,r,x);
101     }
102 }
103 int dist(int x,int y)
104 {
105   int z=lca(x,y);
106   return dep[x]+dep[y]-2*dep[z];
107 }
108 void get_dist(int x,int pa,int fa)
109 {int i;
110   q1[root].push(dist(pa,x));
111   for (i=head[x];i;i=edge[i].next)
112     {
113       int v=edge[i].to;
114       if (v==fa||vis[v]) continue;
115       get_dist(v,pa,x);
116     }
117 }
118 void work(int x,int pa)
119 {int i;
120   minsize=2e9;
121   get_size(x,0);get_root(x,x,0);
122   FA[root]=pa;vis[root]=1;
123   q2[root].push(0);q1[root].push(dist(root,pa));
124   for (i=head[root];i;i=edge[i].next)
125     {
126       int v=edge[i].to;
127       if (vis[v]) continue;
128       get_dist(v,pa,root);
129     }
130   q2[pa].push(q1[root].top());
131   int rt=root;
132   for (i=head[root];i;i=edge[i].next)
133     {
134       int v=edge[i].to;
135       if (vis[v]) continue;
136       work(v,rt);    
137     }
138   if (q2[rt].size()>=2)
139     q3.push(q2[rt].top()+q2[rt].sec());
140 }
141 void trunon(int x)
142 {int i;
143   if (q2[x].size()>=2)
144     q3.erase(q2[x].top()+q2[x].sec());
145   q2[x].erase(0);
146   if (q2[x].size()>=2)
147     q3.push(q2[x].top()+q2[x].sec());
148   for (i=x;FA[i];i=FA[i])
149     {
150       if (q2[FA[i]].size()>=2) q3.erase(q2[FA[i]].top()+q2[FA[i]].sec());
151       if (q1[i].size()) q2[FA[i]].erase(q1[i].top());
152       q1[i].erase(dist(x,FA[i]));
153       if (q1[i].size()) q2[FA[i]].push(q1[i].top());
154       if (q2[FA[i]].size()>=2) q3.push(q2[FA[i]].top()+q2[FA[i]].sec());
155     }
156 }
157 void trunoff(int x)
158 {int i;
159     if (q2[x].size()>=2)
160     q3.erase(q2[x].top()+q2[x].sec());
161     q2[x].push(0);
162     if (q2[x].size()>=2)
163     q3.push(q2[x].top()+q2[x].sec());
164     for (i=x;FA[i];i=FA[i])
165       {
166     if (q2[FA[i]].size()>=2) q3.erase(q2[FA[i]].top()+q2[FA[i]].sec());
167     if (q1[i].size()) q2[FA[i]].erase(q1[i].top());
168     q1[i].push(dist(x,FA[i]));
169     if (q1[i].size()) q2[FA[i]].push(q1[i].top());
170     if (q2[FA[i]].size()>=2) q3.push(q2[FA[i]].top()+q2[FA[i]].sec());
171       }
172 }
173 int main()
174 {int i,u,v,j,x;
175   cin>>n;
176   for (i=1;i<=n-1;i++)
177     {
178       scanf("%d%d",&u,&v);
179       add(u,v);add(v,u);
180     }
181   cin>>m;
182   dfs(1,0);
183   for (i=1;i<=20;i++)
184     {
185       for (j=1;j<=n;j++)
186     fa[j][i]=fa[fa[j][i-1]][i-1];
187     }
188   work(1,0);
189   cnt=n;
190   for (i=1;i<=m;i++)
191     {
192       scanf("%s",ch);
193       if (ch[0]=='G')
194     {
195       if (cnt<=1) printf("%d\n",cnt-1);
196       else printf("%d\n",q3.top());
197     }
198       else
199     {
200       scanf("%d",&x);
201       if (light[x]==0) trunon(x),cnt--;
202       else trunoff(x),cnt++;
203       light[x]^=1;
204     }
205     }
206 }

 

posted @ 2018-01-22 16:35  Z-Y-Y-S  阅读(315)  评论(0编辑  收藏  举报