洛谷 P2056 [ZJOI2007]捉迷藏 || bzoj 1095: [ZJOI2007]Hide 捉迷藏 || 洛谷 P4115 Qtree4 || SP2666 QTREE4 - Query on a tree IV
意识到一点:在进行点分治时,每一个点都会作为某一级重心出现,且任意一点只作为重心恰好一次。因此原树上任意一个节点都会出现在点分树上,且是恰好一次
https://www.cnblogs.com/zzqsblog/p/6393023.html
对比http://www.cnblogs.com/hehe54321/p/8570320.html的普通点分程序,"到分治树上这个点父亲的距离"相当于solve(u)时各个cal函数计算出的值对ans的总贡献,只不过改成了动态维护这个值。
普通点分由"分治树上这个点父亲"来计算"这个点"的贡献,需要容斥解决(当然这道题维护所求值不需要容斥);这道题则维护某个重心管辖的连通块中各个点到该重心的上层重心的距离,这样修改某个点的贡献时,就可以修改该点到最上层重心的各个点维护的关于该点的信息。
不能维护各个点到该重心的距离,一定要维护到上层重心的距离,否则无法区分开各个子树。
(失败代码:
#include<cstdio> #include<algorithm> #include<set> using namespace std; struct E { int to,nxt; }e[200100]; int f1[100100],ne; int ff[100100],n,sum,fx[100100],dep[100100],sz[100100]; int eu[200100],pos[100100],dpx[200100],st[200100][20],log2x[200100]; int root; bool fl[100100],vis[100100]; multiset<int> s[100100],s2; //s[i]:i点管辖的连通块各个点到i点的距离 //s2:各个s的最大值 int getdis(int x,int y) { int l=pos[x],r=pos[y];if(l>r) swap(l,r); int k=log2x[r-l+1],t=dpx[pos[st[l][k]]]>dpx[pos[st[r-(1<<k)+1][k]]]?st[r-(1<<k)+1][k]:st[l][k]; return dpx[pos[x]]+dpx[pos[y]]-2*dpx[pos[t]]; } void getroot(int u,int fa) { sz[u]=1;fx[u]=0; for(int k=f1[u];k;k=e[k].nxt) if(!vis[e[k].to]&&e[k].to!=fa) { getroot(e[k].to,u); sz[u]+=sz[e[k].to]; fx[u]=max(fx[u],sz[e[k].to]); } fx[u]=max(fx[u],sum-sz[u]); if(fx[u]<fx[root]) root=u; } void getsz(int u,int fa) { sz[u]=1; for(int k=f1[u];k;k=e[k].nxt) if(!vis[e[k].to]&&e[k].to!=fa) { getsz(e[k].to,u); sz[u]+=sz[e[k].to]; } } void getdeep(int u,int fa) { s[root].insert(dep[u]); for(int k=f1[u];k;k=e[k].nxt) if(!vis[e[k].to]&&e[k].to!=fa) { dep[e[k].to]=dep[u]+1; getdeep(e[k].to,u); } } char tmp[20]; int getmax2(int p) { if(s[p].size()<2) return -0x3f3f3f3f; auto it=s[p].rbegin();int ans=0; ans+=*it;++it;ans+=*it; return ans; } void solve(int u) { vis[u]=1; dep[u]=0;getdeep(u,0);s2.insert(getmax2(u)); for(int k=f1[u];k;k=e[k].nxt) if(!vis[e[k].to]) { getsz(e[k].to,0);sum=sz[e[k].to]; root=0;getroot(e[k].to,0); ff[root]=u; solve(root); } } void dfs1(int u,int fa,int d) { eu[++eu[0]]=u;pos[u]=eu[0];dpx[eu[0]]=d; for(int k=f1[u];k;k=e[k].nxt) if(e[k].to!=fa) { dfs1(e[k].to,u,d+1); eu[++eu[0]]=u; dpx[eu[0]]=d; } } void debugxxxx(multiset<int>& s) { for(auto i : s) printf("%d ",i); puts("test"); } void change(int u) { int now; for(now=u;now;now=ff[now]) { s2.erase(s2.find(getmax2(now))); if(!fl[u]) s[now].erase(s[now].find(getdis(u,now))); } fl[u]^=1; for(now=u;now;now=ff[now]) { if(!fl[u]) s[now].insert(getdis(u,now)); s2.insert(getmax2(now)); } } int main() { fx[0]=0x3f3f3f3f; int i,j,a,b,la=0,q,t; for(i=1;i<=200000;i++) { if(i>=(1<<(la+1))) ++la; log2x[i]=la; } scanf("%d",&n); for(i=1;i<n;i++) { scanf("%d%d",&a,&b); e[++ne].to=b;e[ne].nxt=f1[a];f1[a]=ne; e[++ne].to=a;e[ne].nxt=f1[b];f1[b]=ne; } dfs1(1,0,0); for(i=1;i<=eu[0];i++) st[i][0]=eu[i]; for(j=1;(1<<j)<=eu[0];j++) for(i=1;i+(1<<j)-1<=eu[0];i++) if(dpx[pos[st[i][j-1]]]>dpx[pos[st[i+(1<<(j-1))][j-1]]]) st[i][j]=st[i+(1<<(j-1))][j-1]; else st[i][j]=st[i][j-1]; //getdis(5,4); sum=n;getroot(1,0); solve(root); scanf("%d",&q); while(q--) { scanf("%s",tmp); if(tmp[0]=='G') { printf("%d\n",*s2.rbegin()); } else if(tmp[0]=='C') { scanf("%d",&t); change(t); } } return 0; }
)
最终代码(洛谷A不掉,好像被卡常了?)
#pragma GCC optimize("Ofast") #pragma GCC optimize("inline","fast-math","unroll-loops","no-stack-protector") #pragma GCC diagnostic error "-fwhole-program" #pragma GCC diagnostic error "-fcse-skip-blocks" #pragma GCC diagnostic error "-funsafe-loop-optimizations" #pragma GCC diagnostic error "-std=c++14" #include<cstdio> #include<algorithm> #include<set> using namespace std; struct E { int to,nxt; }e[200100]; int f1[100100],ne; int ff[100100],n,sum,fx[100100],sz[100100]; int eu[200100],pos[200100],dpx[200100],st[200100][20],log2x[200100],lft[30]; int root; bool fl[100100],vis[100100]; multiset<int> s[100100],s2[100100],s3; //s[i]:i点管辖的连通块各个点到i点上层重心的距离 //s2[i]:i点的各个下层重心的s的最大值,**再加上一个0(i点到自身距离) //s3:各个s2的前2大值之和 int getdis(int x,int y) { int l=pos[x],r=pos[y];if(l>r) swap(l,r); int k=log2x[r-l+1],t=dpx[pos[st[l][k]]]>dpx[pos[st[r-lft[k]+1][k]]]?st[r-lft[k]+1][k]:st[l][k]; return dpx[pos[x]]+dpx[pos[y]]-2*dpx[pos[t]]; } void getroot(int u,int fa) { sz[u]=1;fx[u]=0; for(int k=f1[u];k;k=e[k].nxt) if(!vis[e[k].to]&&e[k].to!=fa) { getroot(e[k].to,u); sz[u]+=sz[e[k].to]; fx[u]=max(fx[u],sz[e[k].to]); } fx[u]=max(fx[u],sum-sz[u]); if(fx[u]<fx[root]) root=u; } void getsz(int u,int fa) { sz[u]=1; for(int k=f1[u];k;k=e[k].nxt) if(!vis[e[k].to]&&e[k].to!=fa) { getsz(e[k].to,u); sz[u]+=sz[e[k].to]; } } void getdeep(int u,int fa) { s[root].insert(getdis(u,ff[root])); for(int k=f1[u];k;k=e[k].nxt) if(!vis[e[k].to]&&e[k].to!=fa) getdeep(e[k].to,u); } char tmp[20]; int getmax2(int p) { if(s2[p].size()<2) return -0x3f3f3f3f; multiset<int>::reverse_iterator it=s2[p].rbegin();int ans=0; ans+=*it;++it;ans+=*it; return ans; } void solve(int u) { vis[u]=1; s2[u].insert(0); for(int k=f1[u];k;k=e[k].nxt) if(!vis[e[k].to]) { getsz(e[k].to,0);sum=sz[e[k].to]; root=0;getroot(e[k].to,0); ff[root]=u;getdeep(root,0); if(!s[root].empty()) s2[u].insert(*s[root].rbegin()); solve(root); } s3.insert(getmax2(u)); } void dfs1(int u,int fa,int d) { eu[++eu[0]]=u;pos[u]=eu[0];dpx[eu[0]]=d; for(int k=f1[u];k;k=e[k].nxt) if(e[k].to!=fa) { dfs1(e[k].to,u,d+1); eu[++eu[0]]=u; dpx[eu[0]]=d; } } //void debugxxxx(multiset<int>& s) //{ // for(auto i : s) printf("%d ",i); // puts("test"); //} void change(int u) { int now; s3.erase(s3.find(getmax2(u))); if(!fl[u]) s2[u].erase(s2[u].find(0)); for(now=u;ff[now];now=ff[now]) { s3.erase(s3.find(getmax2(ff[now]))); if(!s[now].empty()) s2[ff[now]].erase(s2[ff[now]].find(*s[now].rbegin())); if(!fl[u]) s[now].erase(s[now].find(getdis(u,ff[now]))); } fl[u]^=1; if(!fl[u]) s2[u].insert(0); s3.insert(getmax2(u)); for(now=u;ff[now];now=ff[now]) { if(!fl[u]) s[now].insert(getdis(u,ff[now])); if(!s[now].empty()) s2[ff[now]].insert(*s[now].rbegin()); s3.insert(getmax2(ff[now])); } } int num; int main() { lft[0]=1; fx[0]=0x3f3f3f3f; int i,j,a,b,la=0,q,t; for(i=1;i<=27;i++) lft[i]=(lft[i-1]<<1); for(i=1;i<=200000;i++) { if(i>=lft[la+1]) ++la; log2x[i]=la; } scanf("%d",&n); for(i=1;i<n;i++) { scanf("%d%d",&a,&b); e[++ne].to=b;e[ne].nxt=f1[a];f1[a]=ne; e[++ne].to=a;e[ne].nxt=f1[b];f1[b]=ne; } dfs1(1,0,0); for(i=1;i<=eu[0];i++) st[i][0]=eu[i]; for(j=1;(1<<j)<=eu[0];j++) for(i=1;i+lft[j]-1<=eu[0];i++) if(dpx[pos[st[i][j-1]]]>dpx[pos[st[i+lft[j-1]][j-1]]]) st[i][j]=st[i+lft[j-1]][j-1]; else st[i][j]=st[i][j-1]; sum=n;getroot(1,0); solve(root); scanf("%d",&q); num=n; while(q--) { scanf("%s",tmp); if(tmp[0]=='G') { if(num==0) printf("-1\n"); else if(num==1) printf("0\n"); else printf("%d\n",*s3.rbegin()); } else if(tmp[0]=='C') { scanf("%d",&t); if(fl[t]) num++;else num--; change(t); } } return 0; }
Qtree4卡不过去...算了不卡了,反正对拍没对出错(本地n=100000,q=100000随机数据1.5秒)
1 #pragma GCC optimize("Ofast") 2 #pragma GCC optimize("inline","fast-math","unroll-loops","no-stack-protector") 3 #pragma GCC diagnostic error "-fwhole-program" 4 #pragma GCC diagnostic error "-fcse-skip-blocks" 5 #pragma GCC diagnostic error "-funsafe-loop-optimizations" 6 #pragma GCC diagnostic error "-std=c++14" 7 #include<cstdio> 8 #include<algorithm> 9 #include<set> 10 using namespace std; 11 struct E 12 { 13 int to,nxt,d; 14 }e[200100]; 15 int f1[100100],ne; 16 int ff[100100],n,sum,fx[100100],sz[100100]; 17 int eu[200100],pos[200100],dpx[200100],dpx2[200100],st[200100][20],log2x[200100],lft[30]; 18 int root; 19 bool fl[100100],vis[100100]; 20 multiset<int> s[100100],s2[100100],s3; 21 //s[i]:i点管辖的连通块各个点到i点上层重心的距离 22 //s2[i]:i点的各个下层重心的s的最大值,**再加上一个0(i点到自身距离) 23 //s3:各个s2的前2大值之和 24 int getdis(int x,int y) 25 { 26 int l=pos[x],r=pos[y];if(l>r) swap(l,r); 27 int k=log2x[r-l+1],t=dpx[pos[st[l][k]]]>dpx[pos[st[r-lft[k]+1][k]]]?st[r-lft[k]+1][k]:st[l][k]; 28 return dpx2[pos[x]]+dpx2[pos[y]]-2*dpx2[pos[t]]; 29 } 30 void getroot(int u,int fa) 31 { 32 sz[u]=1;fx[u]=0; 33 for(int k=f1[u];k;k=e[k].nxt) 34 if(!vis[e[k].to]&&e[k].to!=fa) 35 { 36 getroot(e[k].to,u); 37 sz[u]+=sz[e[k].to]; 38 fx[u]=max(fx[u],sz[e[k].to]); 39 } 40 fx[u]=max(fx[u],sum-sz[u]); 41 if(fx[u]<fx[root]) root=u; 42 } 43 void getsz(int u,int fa) 44 { 45 sz[u]=1; 46 for(int k=f1[u];k;k=e[k].nxt) 47 if(!vis[e[k].to]&&e[k].to!=fa) 48 { 49 getsz(e[k].to,u); 50 sz[u]+=sz[e[k].to]; 51 } 52 } 53 void getdeep(int u,int fa) 54 { 55 s[root].insert(getdis(u,ff[root])); 56 for(int k=f1[u];k;k=e[k].nxt) 57 if(!vis[e[k].to]&&e[k].to!=fa) 58 getdeep(e[k].to,u); 59 } 60 char tmp[20]; 61 int getmax2(int p) 62 { 63 if(s2[p].size()<2) return -0x3f3f3f3f; 64 multiset<int>::reverse_iterator it=s2[p].rbegin();int ans=0; 65 ans+=*it;++it;ans+=*it; 66 return ans; 67 } 68 void solve(int u) 69 { 70 vis[u]=1; 71 s2[u].insert(0); 72 for(int k=f1[u];k;k=e[k].nxt) 73 if(!vis[e[k].to]) 74 { 75 getsz(e[k].to,0);sum=sz[e[k].to]; 76 root=0;getroot(e[k].to,0); 77 ff[root]=u;getdeep(root,0); 78 if(!s[root].empty()) s2[u].insert(*s[root].rbegin()); 79 solve(root); 80 } 81 s3.insert(getmax2(u)); 82 } 83 void dfs1(int u,int fa,int d,int d2) 84 { 85 eu[++eu[0]]=u;pos[u]=eu[0];dpx[eu[0]]=d;dpx2[eu[0]]=d2; 86 for(int k=f1[u];k;k=e[k].nxt) 87 if(e[k].to!=fa) 88 { 89 dfs1(e[k].to,u,d+1,d2+e[k].d); 90 eu[++eu[0]]=u; 91 dpx[eu[0]]=d; 92 dpx2[eu[0]]=d2; 93 } 94 } 95 //void debugxxxx(multiset<int>& s) 96 //{ 97 // for(auto i : s) printf("%d ",i); 98 // puts("test"); 99 //} 100 void change(int u) 101 { 102 int now; 103 s3.erase(s3.find(getmax2(u))); 104 if(!fl[u]) s2[u].erase(s2[u].find(0)); 105 for(now=u;ff[now];now=ff[now]) 106 { 107 s3.erase(s3.find(getmax2(ff[now]))); 108 if(!s[now].empty()) s2[ff[now]].erase(s2[ff[now]].find(*s[now].rbegin())); 109 if(!fl[u]) s[now].erase(s[now].find(getdis(u,ff[now]))); 110 } 111 fl[u]^=1; 112 if(!fl[u]) s2[u].insert(0); 113 s3.insert(getmax2(u)); 114 for(now=u;ff[now];now=ff[now]) 115 { 116 if(!fl[u]) s[now].insert(getdis(u,ff[now])); 117 if(!s[now].empty()) s2[ff[now]].insert(*s[now].rbegin()); 118 s3.insert(getmax2(ff[now])); 119 } 120 } 121 int num; 122 int main() 123 { 124 lft[0]=1; 125 fx[0]=0x3f3f3f3f; 126 int i,j,a,b,la=0,q,t,c; 127 for(i=1;i<=27;i++) lft[i]=(lft[i-1]<<1); 128 for(i=1;i<=200000;i++) 129 { 130 if(i>=lft[la+1]) ++la; 131 log2x[i]=la; 132 } 133 scanf("%d",&n); 134 for(i=1;i<n;i++) 135 { 136 scanf("%d%d%d",&a,&b,&c); 137 e[++ne].to=b;e[ne].nxt=f1[a];e[ne].d=c;f1[a]=ne; 138 e[++ne].to=a;e[ne].nxt=f1[b];e[ne].d=c;f1[b]=ne; 139 } 140 dfs1(1,0,0,0); 141 for(i=1;i<=eu[0];i++) st[i][0]=eu[i]; 142 for(j=1;(1<<j)<=eu[0];j++) 143 for(i=1;i+lft[j]-1<=eu[0];i++) 144 if(dpx[pos[st[i][j-1]]]>dpx[pos[st[i+lft[j-1]][j-1]]]) 145 st[i][j]=st[i+lft[j-1]][j-1]; 146 else 147 st[i][j]=st[i][j-1]; 148 sum=n;getroot(1,0); 149 solve(root); 150 scanf("%d",&q); 151 num=n; 152 while(q--) 153 { 154 scanf("%s",tmp); 155 if(tmp[0]=='A') 156 { 157 if(num==0) printf("They have disappeared.\n"); 158 else if(num==1) printf("0\n"); 159 else printf("%d\n",max(*s3.rbegin(),0)); 160 } 161 else if(tmp[0]=='C') 162 { 163 scanf("%d",&t); 164 if(fl[t]) num++;else num--; 165 change(t); 166 } 167 } 168 return 0; 169 }
数据生成器
var random = Math.random, floor = Math.floor, exit = process.exit, print = console.log; var n = 100000, q = 100000; console.log(n); var fa = new Array(n+1), a, b, ta, tb, idx; for(i=1; i<=n; i++) fa[i] = i; function find(x) {return x===fa[x]?x:fa[x]=find(fa[x]);} for(i=1; i<n; i++) { do { a = floor(random()*n) + 1; b = floor(random()*n) + 1; ta = find(a);tb = find(b); } while(ta == tb); fa[ta] = tb; console.log(a+" "+b+" "+(floor(random()*21)-10)); } console.log(q); for(i=1; i<=q; i++) { idx = floor(random()*2); if (idx === 1) { console.log("A"); } else { console.log("C "+(floor(random()*n)+1)); } }
另有:捉迷藏特殊做法