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。
我有多久没碰博客了ojz大概是最近太怠惰了吧……
然后最近在学点分治,Zn_H神犇就唆使我做这道题咯QAQ
还是太神了看了题解想了好久才懂……
先建一个重心树,这个的意思就是,通过点分治的过程,找到每一个层的重心,然后用这些重心上一层重心连下一层这样建一个树。
这样可以保证重心树深度小于等于logn。
然后对于每个点建两个堆,
第一个堆s1表示:该点的所有子树的点到其重心树上的父亲的距离。
第二个堆s2表示:该点在重心树上的所有子树的点的堆s1的top值。
再用一个ans堆记录每个点的堆s2上最大值和次大值之和,询问答案即取top即可。
删除操作和插入操作就对这两个堆进行修改。
可以这么理解:
每次修改后我们可以在每次向上更新时,先删去在ans堆的中的目前点的重心树上父亲的s2堆的最大值和次大值之和,再删去目前点的重心树上父亲的s2堆中,目前点的s1堆的top值。然后操作,插入/删除目前点的重心树上父亲到x(操作的那个点)的距离。最后再插入目前点的重心树上父亲的s2堆中,目前点的s1堆的top值,再在ans堆中插入目前点的重心树上父亲的s2堆的最大值和次大值之和。(各种拗口总之看代码其实很好懂)
代码这样QAQ(看有dalao只写了120+行,佩服ojz)
1 #include<iostream> 2 #include<cstdio> 3 #include<cstdlib> 4 #include<cstring> 5 #include<cmath> 6 #include<queue> 7 #include<algorithm> 8 using namespace std; 9 #define maxm 500005 10 #define maxn 100100 11 12 int read() 13 { 14 int f=1,p=0; 15 char c=getchar(); 16 while (c<'0'||c>'9'){if (c=='-')f=-1;c=getchar();} 17 while (c>='0'&&c<='9'){p=p*10+c-'0';c=getchar();} 18 return f*p; 19 } 20 21 int n,m,cnt=0,all,rt,T=0,tot=0; 22 int son[maxn],f[maxn],fa[maxn],pos[maxn],dep[maxn],a[maxn<<1][20]; 23 int lg2[maxn<<1],head[maxn],can[maxn]; 24 bool cdt[maxn]; 25 struct edge{int u,v,next;}e[maxn<<1]; 26 27 struct node 28 { 29 priority_queue<int> heap,delmark; 30 31 void ins(int x) 32 {heap.push(x);} 33 void del(int x) 34 {delmark.push(x);} 35 void POP() 36 { 37 while (delmark.size()&&delmark.top()==heap.top()) 38 delmark.pop(),heap.pop(); 39 heap.pop(); 40 } 41 int TOP() 42 { 43 while (delmark.size()&&delmark.top()==heap.top()) 44 delmark.pop(),heap.pop(); 45 return heap.top(); 46 } 47 int sdTOP() 48 { 49 int ls=TOP();POP(); 50 int ret=TOP();ins(ls); 51 return ret; 52 } 53 int SIZE() 54 { 55 return heap.size()-delmark.size(); 56 } 57 }s1[maxn],s2[maxn],ans; 58 59 void addedge(int u,int v) 60 { 61 cnt++;e[cnt].u=u;e[cnt].v=v; 62 e[cnt].next=head[u];head[u]=cnt; 63 } 64 void getroot(int x,int pa) 65 { 66 son[x]=1;f[x]=0; 67 for (int i=head[x];i;i=e[i].next) 68 { 69 int y=e[i].v; 70 if (can[y]||y==pa) continue; 71 getroot(y,x); 72 son[x]+=son[y]; 73 if (son[y]>f[x]) f[x]=son[y]; 74 } 75 if (all-son[x]>f[x]) f[x]=all-son[x]; 76 if (f[x]<f[rt]) rt=x; 77 } 78 void dfs(int x,int pa,int dep,node &s) 79 { 80 s.ins(dep); 81 for (int i=head[x];i;i=e[i].next) 82 { 83 int y=e[i].v; 84 if (can[y]||y==pa) continue; 85 dfs(y,x,dep+1,s); 86 } 87 } 88 void insert(node &s) 89 { 90 if (s.SIZE()>=2) 91 { 92 int tmp=s.TOP()+s.sdTOP(); 93 ans.ins(tmp); 94 } 95 } 96 void erase(node &s) 97 { 98 if (s.SIZE()>=2) 99 { 100 int tmp=s.TOP()+s.sdTOP(); 101 ans.del(tmp); 102 } 103 } 104 void work(int x) 105 { 106 can[x]=1; 107 s2[x].ins(0); 108 for (int i=head[x];i;i=e[i].next) 109 { 110 int y=e[i].v; 111 if (can[y]) continue; 112 node s; 113 dfs(y,x,1,s); 114 all=son[y];f[rt=0]=n+1; 115 getroot(y,0); 116 int ls=rt;work(rt); 117 fa[ls]=x;s1[ls]=s; 118 s2[x].ins(s.TOP()); 119 } 120 insert(s2[x]); 121 } 122 void getdep(int x,int pa) 123 { 124 a[pos[x]=++T][0]=dep[x]=dep[pa]+1; 125 for (int i=head[x];i;i=e[i].next) 126 { 127 int y=e[i].v; 128 if (y==pa) continue; 129 getdep(y,x); 130 a[++T][0]=dep[x]; 131 } 132 } 133 int lcadep(int x,int y) 134 { 135 x=pos[x],y=pos[y]; 136 if (x>y) swap(x,y); 137 int ls=lg2[y-x+1]; 138 return min(a[x][ls],a[y-(1<<ls)+1][ls]); 139 } 140 int dis(int x,int y) 141 { 142 return dep[x]+dep[y]-2*lcadep(x,y); 143 } 144 void turnoff(int x) 145 { 146 erase(s2[x]); 147 s2[x].ins(0); 148 insert(s2[x]); 149 for (int i=x;fa[i];i=fa[i]) 150 { 151 erase(s2[fa[i]]); 152 if (s1[i].SIZE()) 153 s2[fa[i]].del(s1[i].TOP()); 154 s1[i].ins(dis(fa[i],x)); 155 if (s1[i].SIZE()) 156 s2[fa[i]].ins(s1[i].TOP()); 157 insert(s2[fa[i]]); 158 } 159 } 160 void turnon(int x)//del 161 { 162 erase(s2[x]); 163 s2[x].del(0); 164 insert(s2[x]); 165 for (int i=x;fa[i];i=fa[i]) 166 { 167 erase(s2[fa[i]]); 168 if (s1[i].SIZE()) 169 s2[fa[i]].del(s1[i].TOP()); 170 s1[i].del(dis(fa[i],x)); 171 if (s1[i].SIZE()) 172 s2[fa[i]].ins(s1[i].TOP()); 173 insert(s2[fa[i]]); 174 } 175 } 176 177 int main() 178 { 179 freopen("hide.in","r",stdin); 180 freopen("hide.out","w",stdout); 181 n=read(); 182 for (int i=1;i<n;i++) 183 { 184 int u=read(),v=read(); 185 addedge(u,v); 186 addedge(v,u); 187 } 188 f[rt=0]=n+1;all=n; 189 getroot(1,0);work(rt);getdep(1,0); 190 for (int i=2;i<=T;i++) 191 lg2[i]=lg2[i>>1]+1; 192 for (int j=1;j<=lg2[T];j++) 193 for (int i=1;i+(1<<j)-1<=T;i++) 194 a[i][j]=min(a[i][j-1],a[i+(1<<j-1)][j-1]); 195 //0是关灯,1是开灯 196 m=read();tot=n; 197 char op[10]; 198 for (int i=1;i<=m;i++) 199 { 200 scanf("%s",op); 201 if (op[0]=='C') 202 { 203 int ch=read(); 204 if (cdt[ch]) 205 { 206 tot++;cdt[ch]=0; 207 turnoff(ch); 208 } 209 else 210 { 211 tot--;cdt[ch]=1; 212 turnon(ch); 213 } 214 } 215 else 216 { 217 if (tot<=1) printf("%d\n",tot-1); 218 else printf("%d\n",ans.TOP()); 219 } 220 } 221 fclose(stdin); 222 fclose(stdout); 223 return 0; 224 }
就酱w总算是搞完这题了天哪噜。