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

Sample Output

4
3
3
4

HINT

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

Solution

维护三个堆。

$h1[x]$存当前重心$x$管辖的范围内的点到$x$在点分树上的父亲的所有距离。

$h2[x]$存$x$在点分树上所有儿子的$h1$堆的堆顶。

$h3$存每个点的答案。

关灯的点$h2$自带一个$0$方便处理单链……

反正快退役了也不想写太多了……还有问题看代码吧……

Code

  1 #include<iostream>
  2 #include<cstring>
  3 #include<cstdio>
  4 #include<queue>
  5 #define N (100009)
  6 using namespace std;
  7 
  8 struct Heap
  9 {
 10     priority_queue<int>q,del;
 11     void push(int x) {q.push(x);}
 12     void erase(int x) {del.push(x);}
 13     bool empty() {return q.size()-del.size()==0;}
 14     int size() {return q.size()-del.size();}
 15     int top()
 16     {
 17         while (!del.empty() && q.top()==del.top()) q.pop(), del.pop();
 18         return q.top();
 19     }
 20     void pop()
 21     {
 22         while (!del.empty() && q.top()==del.top()) q.pop(), del.pop();
 23         return q.pop();
 24     }
 25     int sec()
 26     {
 27         if (size()<2) return -1;
 28         int tmp1=top(); pop();
 29         int tmp2=top(); push(tmp1);
 30         return tmp2;
 31     }
 32 }h1[N],h2[N],h3;
 33 
 34 struct Edge{int to,next;}edge[N<<1];
 35 int n,m,root,sum,light_num;
 36 int s[N],f[N][17],fa[N],dep[N],maxsize[N],size[N],vis[N];
 37 int head[N],num_edge;
 38 
 39 inline int read()
 40 {
 41     int x=0,w=1; char c=getchar();
 42     while (c<'0' || c>'9') {if (c=='-') w=-1; c=getchar();}
 43     while (c>='0' && c<='9') x=x*10+c-'0', c=getchar();
 44     return x*w;
 45 }
 46 
 47 void add(int u,int v)
 48 {
 49     edge[++num_edge].to=v;
 50     edge[num_edge].next=head[u];
 51     head[u]=num_edge;
 52 }
 53 
 54 void DFS(int x,int fa)
 55 {
 56     dep[x]=dep[fa]+1; f[x][0]=fa;
 57     for (int i=1; i<=16; ++i) f[x][i]=f[f[x][i-1]][i-1];
 58     for (int i=head[x]; i; i=edge[i].next)
 59         if (edge[i].to!=fa) DFS(edge[i].to,x);
 60 }
 61 
 62 void Get_Root(int x,int fa)
 63 {
 64     size[x]=1; maxsize[x]=0;
 65     for (int i=head[x]; i; i=edge[i].next)
 66         if (!vis[edge[i].to] && edge[i].to!=fa)
 67         {
 68             Get_Root(edge[i].to,x);
 69             size[x]+=size[edge[i].to];
 70             maxsize[x]=max(maxsize[x], size[edge[i].to]);
 71         }
 72     maxsize[x]=max(maxsize[x],sum-size[x]);
 73     if (maxsize[x]<maxsize[root]) root=x;
 74 }
 75 
 76 void Solve(int x)
 77 {
 78     vis[x]=1;
 79     for (int i=head[x]; i; i=edge[i].next)
 80         if (!vis[edge[i].to])
 81         {
 82             sum=size[edge[i].to]; root=0;
 83             Get_Root(edge[i].to,x);
 84             fa[root]=x; Solve(root);
 85         }
 86 }
 87 
 88 int LCA(int x,int y)
 89 {
 90     if (dep[x]<dep[y]) swap(x,y);
 91     for (int i=16; i>=0; --i)
 92         if (dep[f[x][i]]>=dep[y]) x=f[x][i];
 93     if (x==y) return x;
 94     for (int i=16; i>=0; --i)
 95         if (f[x][i]!=f[y][i]) x=f[x][i], y=f[y][i];
 96     return f[x][0];
 97 }
 98 
 99 void Insert(int x)
100 {
101     if (h2[x].size()>=2)
102         h3.push(h2[x].top()+h2[x].sec());
103 }
104 
105 
106 void Delete(int x)
107 {
108     if (h2[x].size()>=2)
109         h3.erase(h2[x].top()+h2[x].sec());
110 }
111 
112 void Turn_off(int x)
113 {
114     Delete(x); h2[x].push(0); Insert(x);
115     light_num--;
116     for (int t=x,ft=fa[t]; ft; t=fa[t],ft=fa[t])
117     {
118         Delete(ft);
119         if (!h1[t].empty()) h2[ft].erase(h1[t].top());
120         h1[t].push(dep[x]+dep[ft]-2*dep[LCA(x,ft)]);
121         h2[ft].push(h1[t].top());
122         Insert(ft);
123     }
124 }
125 
126 void Turn_on(int x)
127 {
128     Delete(x); h2[x].erase(0); Insert(x);
129     light_num++;
130     for (int t=x,ft=fa[t]; ft; t=fa[t],ft=fa[t])
131     {
132         Delete(ft);
133         if (!h1[t].empty()) h2[ft].erase(h1[t].top());
134         h1[t].erase(dep[x]+dep[ft]-2*dep[LCA(x,ft)]);
135         if (!h1[t].empty()) h2[ft].push(h1[t].top());
136         Insert(ft);
137     }
138 }
139 
140 int main()
141 {
142     n=read(); sum=maxsize[0]=n;
143     for (int i=1; i<=n-1; ++i)
144     {
145         int u=read(),v=read();
146         add(u,v); add(v,u);
147     }
148     DFS(1,0);
149     Get_Root(1,0);
150     Solve(root);
151     for (int i=1; i<=n; ++i) Turn_off(i);
152     light_num=0;
153     m=read();
154     while (m--)
155     {
156         char opt=getchar();
157         while (opt!='C' && opt!='G') opt=getchar();
158         if (opt=='C')
159         {
160             int x=read();
161             if (!s[x]) Turn_on(x);
162             else Turn_off(x);
163             s[x]^=1;
164         }
165         else
166         {
167             if (light_num>=n-1) puts(light_num==n?"-1":"0");
168             else printf("%d\n",h3.top());
169         }
170     }
171 }
posted @ 2019-04-02 19:48  Refun  阅读(419)  评论(0编辑  收藏  举报