[bzoj1095][ZJOI2007]Hide 捉迷藏 点分树,动态点分治

Posted Kaiser

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[bzoj1095][ZJOI2007]Hide 捉迷藏 点分树,动态点分治相关的知识,希望对你有一定的参考价值。

【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。

 

C.每个重心存所有子树到其距离
B.每个重心存各个子树最大值,即子结点堆C的最大值
A.全局一个堆,维护答案最大值,存每个堆B的最大值和次大值之和
 
 
 
C的意思是u这个节点,经过u,到达其父亲f的路径的所有距离,
B是维护所有的子节点的C的最大值,
A是维护各个B中的最大值。
 
动态点分治是树上动态添加节点,在这种情况下动态维护点分树的结构
 
这道题目的树的结构是不变的,所以建出点分树即可,
然后维护各个堆的值即可。
 
因为点分树上是log层的,堆维护也是log的,所有每次询问logn
修改logn logn,所有总复杂度是n log^2n
 
计算深度那里十分巧妙,用一个rmq记录,就是通过dfs访问顺序,然后进入一个点记录一次,
这样总共均摊是2*n,和边有关系,
然后rmq记录最小值,发现这个就是lca的深度
然后距离就比较好算了,O(1)算出,
 
  1 #include<cstring>
  2 #include<cmath>
  3 #include<iostream>
  4 #include<cstdio>
  5 #include<algorithm>
  6 #include<queue>
  7 
  8 #define inf 1000000007
  9 #define N 200007
 10 #define ll long long
 11 using namespace std;
 12 inline int read()
 13 {
 14     int x=0,f=1;char ch=getchar();
 15     while(ch<0||ch>9){if (ch==-)f=-1;ch=getchar();}
 16     while(ch>=0&&ch<=9){x=(x<<3)+(x<<1)+ch-0;ch=getchar();}
 17     return x*f;
 18 }
 19 
 20 int n,m,rt,dfn,sum,tot;
 21 int bin[22],Log[N];
 22 int siz[N],f[N],dep[N];
 23 int cnt,hed[N],rea[N],nxt[N];
 24 int mn[19][N],pos[N],fa[N];
 25 bool vis[N],clo[N];
 26 struct heap
 27 {
 28     priority_queue<int> A,B;
 29     void push(int x){A.push(x);}
 30     void erase(int x){B.push(x);}
 31     void pop()
 32     {
 33         while(B.size()&&A.top()==B.top())
 34             A.pop(),B.pop();
 35         A.pop();
 36     }
 37     int top()
 38     {
 39         while(B.size()&&A.top()==B.top())
 40             A.pop(),B.pop();
 41         if(!A.size())return 0;
 42         return A.top();
 43     }
 44     int size(){return A.size()-B.size();}
 45     int stop()
 46     {
 47         if(size()<2)return 0;
 48         int x=top();pop();
 49         int y=top();push(x);
 50         return y;
 51     }
 52 }A,B[100005],C[100005];
 53 
 54 void add(int u,int v)
 55 {
 56     nxt[++cnt]=hed[u];
 57     hed[u]=cnt;
 58     rea[cnt]=v;
 59 }
 60 void dfs(int u,int fa)
 61 {
 62     mn[0][++dfn]=dep[u],pos[u]=dfn;
 63     for (int i=hed[u];i!=-1;i=nxt[i])
 64     {
 65         int v=rea[i];
 66         if (v==fa)continue;
 67         dep[v]=dep[u]+1;
 68         dfs(v,u);
 69         mn[0][++dfn]=dep[u];
 70     }
 71 }
 72 void get_root(int u,int fa)
 73 {
 74     siz[u]=1,f[u]=0;
 75     for (int i=hed[u];i!=-1;i=nxt[i])
 76     {
 77         int v=rea[i];
 78         if (v==fa||vis[v])continue;
 79         get_root(v,u);
 80         siz[u]+=siz[v];
 81         f[u]=max(f[u],siz[v]);
 82     }
 83     f[u]=max(f[u],sum-siz[u]);
 84     if (f[u]<f[rt])rt=u;
 85 }
 86 void divide(int u,int par)
 87 {
 88     fa[u]=par,vis[u]=1;int sums=sum;
 89     for (int i=hed[u];i!=-1;i=nxt[i])
 90     {
 91         int v=rea[i];
 92         if (vis[v])continue;
 93         if (siz[v]>siz[u]) sum=sums-siz[u];
 94         else sum=siz[v];
 95         rt=0;
 96         get_root(v,u);
 97         divide(rt,u);
 98     }
 99 }
100 int rmq(int x,int y)
101 {
102     x=pos[x],y=pos[y];
103     if (y<x)swap(x,y);
104     int t=Log[y-x+1];
105     return min(mn[t][x],mn[t][y-bin[t]+1]);
106 }
107 int dis(int x,int y)
108 {
109     return dep[x]+dep[y]-2*rmq(x,y);
110 }
111 void turn_off(int u,int v)
112 {
113     if (u==v)
114     {
115         B[u].push(0);
116         if (B[u].size()==2)A.push(B[u].top());
117     }
118     if(!fa[u])return;
119     int f=fa[u],D=dis(f,v),tmp=C[u].top();
120     C[u].push(D);
121     if (D>tmp)
122     {
123         int mx=B[f].top()+B[f].stop(),size=B[f].size();
124         if (tmp)B[f].erase(tmp);
125         B[f].push(D);
126         int now=B[f].top()+B[f].stop();
127         if(now>mx)
128         {
129             if (size>=2)A.erase(mx);
130             if (B[f].size()>=2)A.push(now);
131         }
132     }
133     turn_off(f,v);
134 }
135 void turn_on(int u,int v)
136 {
137     if(u==v)
138     {
139         if(B[u].size()==2)A.erase(B[u].top());
140         B[u].erase(0);
141     }
142     if(!fa[u])return;
143     int f=fa[u],D=dis(f,v),tmp=C[u].top();
144     C[u].erase(D);
145     if(D==tmp)
146     {
147         int mx=B[f].top()+B[f].stop(),size=B[f].size();
148         B[f].erase(D);
149         if(C[u].top())B[f].push(C[u].top());
150         int now=B[f].top()+B[f].stop();
151         if(now<mx)
152         {
153             if(size>=2)A.erase(mx);
154             if(B[f].size()>=2)A.push(now);
155         }
156     }
157     turn_on(f,v);
158 }
159 int main()
160 {
161     bin[0]=1;for (int i=1;i<20;i++)bin[i]=bin[i-1]<<1;//2的幂次
162     Log[0]=-1;for (int i=1;i<=200000;i++)Log[i]=Log[i>>1]+1;
163     n=read();memset(hed,-1,sizeof(hed));
164     for(int i=1;i<n;i++)
165     {
166         int u=read(),v=read();
167         add(u,v),add(v,u);
168     }
169     
170     dfs(1,0);//预处理出深度
171     
172     for (int i=1;i<=Log[dfn];i++)
173         for (int j=1;j<=dfn;j++)
174             if (j+bin[i]-1<=dfn) mn[i][j]=min(mn[i-1][j],mn[i-1][j+bin[i-1]]);
175     //预处理,处理出向下走2^x步的到达最浅的点,就是起lca的深度。
176 
177     rt=0,f[0]=inf,sum=n;
178     get_root(1,0),divide(rt,0);
179     for (int i=1;i<=n;i++)
180         clo[i]=true;
181     for (int i=1;i<=n;i++)turn_off(i,i);
182     tot=n;//tot记录当前多少灯是灭的。
183 //    printf("%d\n",A.top());
184 
185     char ch[2];m=read();
186     while(m--)
187     {
188         scanf("%s",ch+1);
189         if (ch[1]==G)
190         {
191             if (tot<=1) printf("%d\n",tot-1);
192             else printf("%d\n",A.top());
193         }
194         else
195         {
196             int x=read();
197             if (clo[x])turn_on(x,x),tot--;
198             else turn_off(x,x),tot++;
199             clo[x]^=1;
200         }
201     }
202 }

 

 
 
 

以上是关于[bzoj1095][ZJOI2007]Hide 捉迷藏 点分树,动态点分治的主要内容,如果未能解决你的问题,请参考以下文章

bzoj1095: [ZJOI2007]Hide 捉迷藏

BZOJ1095[ZJOI2007]Hide 捉迷藏 动态树分治+堆

[bzoj1095][ZJOI2007]Hide 捉迷藏 点分树,动态点分治

bzoj 1095[ZJOI2007]Hide 捉迷藏

Bzoj1095 [ZJOI2007]Hide 捉迷藏

bzoj千题计划252:bzoj1095: [ZJOI2007]Hide 捉迷藏