bzoj1095: [ZJOI2007]Hide 捉迷藏 动态点分治学习
好迷啊。。。感觉动态点分治就是个玄学,蜜汁把树的深度缩到logn
(静态)点分治大概是递归的时候分类讨论:
1.答案经过当前点,暴力(雾)算
2.答案不经过当前点,继续递归
由于原树可以长的奇形怪状(菊花啊、、链啊、、扫把啊、、)这就导致各种方法都会被卡
于是通过每次找重心保证最大深度
动态怎么解决呢?
不妨考虑线段树是二分的固态版本(只可意会),那么我们把每次找到的重心固定下来长成一棵树就可以把点分治凝固(不可言传)
原来点分治该维护什么现在就维护什么。。。
(事实上我并没有写过静态点分治。。。好气啊╮(╯▽╰)╭)
我居然一度认为新建的树的节点要连到所在子树外一定要经过该子树的根。。。太思博了
实现细节:
1.有一个带删堆,直接拉了板子(拉了才知道实现那么简单,本来以为手打)
2.lca以前习惯rmq(复杂度优异就是自信),现在改成倍增了(可能是之前写了个长链剖分的缘故)
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int Mn=100005; 4 int cnt=0,h[Mn],n,m,vst[Mn],maxx,tg,s[Mn],sz,prt[Mn]; 5 int d[Mn],p[Mn][21],co[Mn]; 6 struct Priority_Queue{ 7 priority_queue<int> q,del; 8 void push(int x) 9 {q.push(x);} 10 void erase(int x){del.push(x);} 11 int top() 12 { 13 while(del.size()&&del.top()==q.top()) 14 {del.pop();q.pop();} 15 return q.top(); 16 } 17 void Pop() 18 { 19 while(del.size()&&del.top()==q.top()) 20 del.pop(),q.pop(); 21 q.pop(); 22 } 23 int sec_top() 24 { 25 int tmp=top();Pop(); 26 int se=top();push(tmp); 27 return se; 28 } 29 int size() 30 { 31 return q.size()-del.size(); 32 } 33 }c[Mn],f[Mn],ans; 34 struct Edge{int to,next;}w[Mn*2]; 35 void add(int x,int y) 36 {w[++cnt]=(Edge){y,h[x]};h[x]=cnt;} 37 void build(int x,int fa) 38 { 39 p[x][0]=fa;d[x]=d[fa]+1; 40 for(int i=1;p[x][i-1];i++) 41 p[x][i]=p[p[x][i-1]][i-1]; 42 for(int i=h[x];i;i=w[i].next) 43 if(w[i].to!=fa) 44 build(w[i].to,x); 45 } 46 void Insert(Priority_Queue &s){ 47 if(s.size()>1)ans.push(s.top()+s.sec_top()); 48 } 49 void Erase(Priority_Queue &s){ 50 if(s.size()>1)ans.erase(s.top()+s.sec_top()); 51 } 52 void DP(int x,int fa) 53 { 54 int j,y;s[x]=1; 55 for(j=h[x];j;j=w[j].next) 56 { 57 y=w[j].to; 58 if(y==fa||vst[y])continue; 59 DP(y,x); 60 s[x]+=s[y]; 61 } 62 } 63 void Biggest(int x,int fa){ 64 int j,y,mx=0; 65 for(j=h[x];j;j=w[j].next){ 66 y=w[j].to; 67 if(y==fa||vst[y])continue; 68 Biggest(y,x); 69 mx=max(mx,s[y]); 70 } 71 if(maxx>max(mx,sz-s[x])){ 72 maxx=max(mx,sz-s[x]); 73 tg=x; 74 } 75 } 76 int gg(int x)//get G 77 { 78 maxx=n+1;tg=0; 79 DP(x,0); 80 sz=s[x]; 81 Biggest(x,0); 82 return tg; 83 } 84 int LCA(int x,int y){ 85 int j; 86 if(d[x]<d[y])swap(x,y); 87 for(j=20;j>=0;j--) 88 if(d[p[x][j]]>=d[y])x=p[x][j]; 89 if(x==y)return x; 90 for(j=20;j>=0;j--) 91 if(p[x][j]!=p[y][j]) 92 {x=p[x][j];y=p[y][j];} 93 return p[x][0]; 94 } 95 int Dis(int x,int y){return d[x]+d[y]-2*d[LCA(x,y)];} 96 void work(int x,int fa,int Gra){ 97 int j,y; 98 f[Gra].push(Dis(x,prt[Gra])); 99 for(j=h[x];j;j=w[j].next){ 100 y=w[j].to; 101 if(y==fa||vst[y])continue; 102 work(y,x,Gra); 103 } 104 } 105 int mzz(int x,int fa) 106 { 107 int j,y,G,Gy; 108 G=gg(x);prt[G]=fa; 109 work(G,0,G); 110 vst[G]=1; 111 c[G].push(0); 112 for(j=h[G];j;j=w[j].next) 113 { 114 y=w[j].to; 115 if(!vst[y]){ 116 Gy=mzz(y,G); 117 c[G].push(f[Gy].top()); 118 } 119 } 120 Insert(c[G]); 121 return G; 122 } 123 void Light(int x){ 124 Erase(c[x]); 125 c[x].erase(0); 126 Insert(c[x]); 127 for(int y=x;prt[y];y=prt[y]){ 128 Erase(c[prt[y]]); 129 if(f[y].size())c[prt[y]].erase(f[y].top()); 130 f[y].erase(Dis(x,prt[y])); 131 if(f[y].size())c[prt[y]].push(f[y].top()); 132 Insert(c[prt[y]]); 133 } 134 } 135 void LiOut(int x){ 136 Erase(c[x]); 137 c[x].push(0); 138 Insert(c[x]); 139 for(int y=x;prt[y];y=prt[y]){ 140 Erase(c[prt[y]]); 141 if(f[y].size())c[prt[y]].erase(f[y].top()); 142 f[y].push(Dis(x,prt[y])); 143 if(f[y].size())c[prt[y]].push(f[y].top()); 144 Insert(c[prt[y]]); 145 } 146 } 147 void solve(){ 148 int i,x;char ch[5]; 149 cnt=n; 150 scanf("%d",&m); 151 for(i=1;i<=m;i++){ 152 scanf("%s",ch); 153 if(ch[0]=='G'){ 154 if(cnt<=1)printf("%d\n",cnt-1); 155 else printf("%d\n",ans.top()); 156 } 157 else{ 158 scanf("%d",&x); 159 if(!co[x]){cnt--;Light(x);co[x]=1;} 160 else{cnt++;LiOut(x);co[x]=0;} 161 } 162 } 163 } 164 int main() 165 { 166 scanf("%d",&n);int x,y; 167 for(int i=1;i<n;i++) 168 scanf("%d%d",&x,&y), 169 add(x,y),add(y,x); 170 build(1,0);mzz(1,0); 171 solve(); 172 return 0; 173 }