洛谷P2056--[ZJOI2007]捉迷藏
阿新 • • 發佈:2018-12-12
今天寫了一晚上的動態點分治,一直寫一直寫,就是寫不出來
無奈對著題解一直寫一直調,超級痛苦
這動態點分治分治其實也不難理解,就是點分樹還有比較暴力的一些操作
複雜度大概在nlog2n,但是寫著就很噁心
最奇怪的是我對於&地址符號的引用開始是不以為意的
但是最後發現T了,無奈照著題解又看,發現原來這就是關鍵點
似乎呼叫&會少一層遞迴,複雜度就會更優秀?
其他的思路還是比較明瞭的
維護一個優先佇列時
開一個優先佇列存有的,一個存刪去的,當重複的時候就直接去掉就可以了
我們一共維護兩個優先佇列,一個表示其分離子樹中每個到它的最長鏈,一個表示其塊內到父重心的最長鏈
然後稍微維護一下就可以了
程式碼如下
#include<bits/stdc++.h> using namespace std; int father[100005][20],to[200005],nxt[200005],head[100005]; int depth[100005],tot,root,sum,size[100005],vis[100005]; int maxa[100005],fa[100005],n,shu1,shu2,shu,cnt; int color[100005],q; char cha; int read() { char c; int x; for(c=getchar();c!='-'&&(c>'9'||c<'0');c=getchar()); if(c=='-') { x=0; for(c=getchar();c>='0'&&c<='9';c=getchar()) x=x*10+c-'0'; return -x; } else { x=c-'0'; for(c=getchar();c>='0'&&c<='9';c=getchar()) x=x*10+c-'0'; return x; } } struct heap { priority_queue <int> a,b; void push(int x){a.push(x);} void pop(int x){b.push(x);} int top() { while(!b.empty()&&a.top()==b.top()) a.pop(),b.pop(); return a.top(); } void pop() { while(!b.empty()&&a.top()==b.top()) a.pop(),b.pop(); a.pop(); } int sectop() { int temp=top();pop(); int re=top();push(temp); return re; } int size() { return a.size()-b.size(); } }one[100005],two[100005],ans; void insert(heap &x) { if(x.size()>=2) ans.push(x.top()+x.sectop());//3 } void erase(heap &x) { if(x.size()>=2) ans.pop(x.top()+x.sectop()); } void add(int x,int y) { to[++tot]=y; nxt[tot]=head[x]; head[x]=tot; } void dfs(int x,int fa) { for(int i=1;i<=18;i++) father[x][i]=father[father[x][i-1]][i-1]; for(int i=head[x];i;i=nxt[i]) { int y=to[i]; if(y==fa) continue; father[y][0]=x; depth[y]=depth[x]+1; dfs(y,x); } } int lca(int x,int y) { if(depth[x]<depth[y]) swap(x,y); int delta=depth[x]-depth[y]; for(int i=0;i<=18;i++) if(delta>>i&1) x=father[x][i]; if(x==y) return x; for(int i=18;i>=0;i--) { if(father[x][i]!=father[y][i]) { x=father[x][i]; y=father[y][i]; } } return father[x][0]; } void findroot(int x,int fa) { size[x]=1;maxa[x]=0; for(int i=head[x];i;i=nxt[i]) { int y=to[i]; if(y==fa||vis[y]) continue; findroot(y,x); size[x]+=size[y]; maxa[x]=max(maxa[x],size[y]); } maxa[x]=max(maxa[x],sum-size[x]); if(maxa[x]<maxa[root]) root=x; } int dis(int x,int y) { return depth[x]+depth[y]-2*depth[lca(x,y)]; } void calc(int x,int fa,int now) { one[root].push(dis(x,now));//1 for(int i=head[x];i;i=nxt[i]) { int y=to[i]; if(vis[y]||y==fa) continue; calc(y,x,now); } } void solve(int x,int faa) { fa[x]=faa; vis[x]=1; two[x].push(0);//2 calc(x,0,faa); for(int i=head[x];i;i=nxt[i]) { int y=to[i]; if(vis[y]) continue; sum=size[y]; root=0; findroot(y,x); int now=root; solve(root,x); two[x].push(one[now].top()); } insert(two[x]); } void turnon(int x) { erase(two[x]); two[x].pop(0); insert(two[x]); for(int y=x;fa[y];y=fa[y]) { erase(two[fa[y]]); if(one[y].size()) two[fa[y]].pop(one[y].top()); one[y].pop(dis(x,fa[y])); if(one[y].size()) two[fa[y]].push(one[y].top()); insert(two[fa[y]]); } } void turnoff(int x) { erase(two[x]); two[x].push(0); insert(two[x]); for(int y=x;fa[y];y=fa[y]) { erase(two[fa[y]]); if(one[y].size()) two[fa[y]].pop(one[y].top()); one[y].push(dis(x,fa[y])); if(one[y].size()) two[fa[y]].push(one[y].top()); insert(two[fa[y]]); } } int main() { cin>>n; for(int i=1;i<=n-1;i++) { shu1=read(); shu2=read(); add(shu1,shu2); add(shu2,shu1); } root=0; size[0]=n; maxa[0]=n; sum=n; depth[1]=1; dfs(1,0); findroot(1,0); solve(root,0); cnt=n; cin>>q; for(int i=1;i<=q;i++) { scanf("\n%c",&cha); if(cha=='G') { if(cnt<=1) printf("%d\n",cnt-1); else printf("%d\n",ans.top()); } else { shu=read(); if(!color[shu]) { color[shu]^=1;turnon(shu);cnt--; } else { color[shu]^=1;turnoff(shu);cnt++; } } } return 0; }