【BZOJ 1095】[ZJOI2007]Hide 捉迷藏 动态树分治

来源:互联网 发布:虚拟主机能部署java吗 编辑:程序博客网 时间:2024/05/16 19:33

一个很烦但是比较容易懂的算法。

先考虑如果我们允许Q*nlogn的复杂度的话怎么写(即每一次的操作都是nlogn的)。

考虑树分治,每一次先找到一个重心然后dfs每一个子树找到每一个子树最深的关灯,然后找到经过这个重心的最远两个点。最后开一个全局变量ans不断地更新ans就好了。

但是显然不能直接这样做,不过幸运的是,我们发现每一次分治的时候其实我们找的重心都是不变的,而从每一个重心dfs下去,每个节点最多之后对logn个点造成贡献,因此,我们其实可以只用做一次树分治,然后储存每一个点会对哪些重心贡献,用链表储存,形成一个新的树,然后由于要支持删除加入操作,就用堆来维护Max就好了,每一次longn次操作。

#include<cstdio>#include<cstring>#include<iostream>#include<cmath>#include<queue>#define maxn 100000 using namespace std;struct myqueue{priority_queue<int>A,B;void push(int x){A.push(x);}void pop(int x){B.push(x);}void del(){while(B.size()&&A.top()==B.top())A.pop(),B.pop();}int top(){del();return A.top();}int size(){return A.size()-B.size();}int query(){del();int x=A.top();A.pop();del();int ans=x+A.top();A.push(x);return ans;}}q1[maxn*2],q2[maxn*2],ans;int n,Q,head[maxn],tot=1,tt=1,last[maxn],dep[maxn],all;int size,s[maxn],f[maxn],rt,vis[maxn],pos[maxn],cnt;struct edge{int v,next;}e[maxn*2];void adde(int a,int b){e[tot].v=b,e[tot].next=head[a];head[a]=tot++;}struct node{int rt,id,dis,next;}nod[maxn*40];void ade(int u,int rt,int id,int dis){nod[tt]=(node){rt,id,dis,last[u]};last[u]=tt++;}void getrt(int u,int fa){s[u]=1,f[u]=0;for(int v,i=head[u];i;i=e[i].next){if(vis[v=e[i].v]||v==fa)continue;getrt(v,u);s[u]+=s[v];f[u]=max(f[u],s[v]);}f[u]=max(f[u],size-s[u]);if(f[u]<f[rt])rt=u;}void dfs(int u,int fa){dep[u]=dep[fa]+1;ade(u,rt,cnt,dep[u]);q1[cnt].push(dep[u]); for(int v,i=head[u];i;i=e[i].next){if(vis[v=e[i].v]||v==fa)continue;dfs(e[i].v,u);}}void solve(int u){vis[u]=1;ade(u,u,0,0);dep[u]=0;q2[u].push(0); for(int v,i=head[u];i;i=e[i].next){if(vis[v=e[i].v])continue;cnt++;dfs(e[i].v,u);q2[u].push(q1[cnt].top()); }for(int v,i=head[u];i;i=e[i].next){if(vis[v=e[i].v])continue;f[rt=0]=size=s[v];getrt(v,u);solve(rt);}if(q2[u].size()>=2)ans.push(q2[u].query());}void turn_off(int u){int rz,dis,id,x,y,z;for(int i=last[u];i;i=nod[i].next){rz=nod[i].rt,id=nod[i].id,dis=nod[i].dis;z=-1;if(!id){if(q2[rz].size()>=2)z=q2[rz].query();q2[rz].push(0);}else{if(q1[id].size())x=q1[id].top();else x=-1;q1[id].push(dis);y=q1[id].top();if(q2[rz].size()>=2)z=q2[rz].query();if(x!=y){if(~x)q2[rz].pop(x);q2[rz].push(y);}}if(z!=-1)ans.pop(z);if(q2[rz].size()>=2)ans.push(q2[rz].query());}}void turn_on(int u){int rz,dis,id,x,y,z,o;for(int i=last[u];i;i=nod[i].next){rz=nod[i].rt,id=nod[i].id,dis=nod[i].dis;z=-1;if(!id){if(q2[rz].size()>=2)z=q2[rz].query();q2[rz].pop(0);}else{x=q1[id].top();q1[id].pop(dis);if(q1[id].size())y=q1[id].top();else y=-1;if(q2[rz].size()>=2)z=q2[rz].query();if(x!=y){q2[rz].pop(x);if(y!=-1)q2[rz].push(y);}}if(z!=-1)ans.pop(z);if(q2[rz].size()>=2)ans.push(q2[rz].query());}}void work(){scanf("%d",&Q);all=n;int a;char s[5];while(Q--){scanf("%s",s);if(s[0]=='G'){if(ans.size())printf("%d\n",ans.top());else if(all==0)puts("-1");else puts("0");}else{scanf("%d",&a);if(pos[a])turn_off(a),all++;else turn_on(a),all--;pos[a]^=1;}}}int main(){scanf("%d",&n);int a,b;for(int i=1;i<n;i++){scanf("%d%d",&a,&b);adde(a,b),adde(b,a);}f[rt=0]=size=n;getrt(1,1);solve(rt);work();return 0;}


0 0
原创粉丝点击