BZOJ 1095: [ZJOI2007]Hide 捉迷藏
Description
一棵树,支持两个操作,修改一个点的颜色,问树上最远的两个白点距离.
Sol
动态点分治.
动态点分治就是将每个重心连接起来,形成一个跟线段树类似的结构,当然它不是二叉的...
这样的树一共有 \(logn\) 层,每个节点维护一些信息.
s1[] 所有子节点到该节点的父重心,也就是上一个重心,所有距离的集合,需要满足插入删除询问最大值的操作,这里我直接用的multiset.
s2[] 所有子重心,就是下面一层的重心,到这个点的最大值分别是多少,需要满足插入删除询问最大值的操作,这里我直接用set.
S答案集合,过所有重心的最长链的集合,就是所有子重心到他的最大值+次大值,需要满足插入删除询问最大值的操作,这里我直接用set.
再加上一个 \(O(1)\) LCA来求一下距离.
这样第一次预处理的时候处理完所有事情,数据修改的时候呢...我的做法比较蠢但是好写,不用考虑那么多乱七八糟的东西..
直接求出整个链,因为一个点对下面的点是没有贡献的,直接向上找出来这一条由重心连成的链.
然后先删掉所有这个节点可能产生的贡献,修改,再重新统计这些节点的最大值..插入同理...
这样复杂度就变成了 \(O(nlog^2n)\) 数据结构有一个 \(log\) ,点分治有一个 \(log\) 修改也是 \(log^2\) 的
打着打着发现自己代码到了6K...其实很大一部分都是调试信息...
Code
/************************************************************** Problem: 1095 User: BeiYu Language: C++ Result: Accepted Time:31445 ms Memory:78796 kb ****************************************************************/ #include <bits/stdc++.h> using namespace std; #define debug(a) cout<<#a<<"="<<a<<" " #define mpr make_pair typedef pair< int,int > pr; const int N = 1e5+50; const int M = 25; int n,m,k,rt,cw; vector< pr > g[N]; int t[N],sz[N],ud[N],cl[N],frt[N]; set< pr,greater< pr > > S; multiset< int,greater< int > > s1[N]; set< pr,greater< pr > > s2[N]; inline int in(int x=0,char ch=getchar()) { while(ch>'9' || ch<'0') ch=getchar(); while(ch>='0' && ch<='9') x=x*10+ch-'0',ch=getchar();return x; } inline char getc(char ch=getchar()) { while(ch>'Z' || ch<'A') ch=getchar();return ch; } void Print(set< pr,greater< pr > > &S) { cout<<"--------start------------"<<endl; for(set< pr >::iterator i=S.begin();i!=S.end();i++) cout<<"("<<(*i).first<<" "<<(*i).second<<") "; cout<<endl<<"----------over-----------"<<endl; } void Print(multiset< int,greater< int > > &S) { cout<<"--------start------------"<<endl; for(multiset< int >::iterator i=S.begin();i!=S.end();i++) cout<<(*i)<<" "; cout<<endl<<"----------over-----------"<<endl; } void SuperPrint() { for(int i=1;i<=n;i++) cout<<frt[i]<<" ";cout<<endl; for(int i=1;i<=n;i++) cout<<i<<endl<<"--> s1[]"<<endl,Print(s1[i]),cout<<"--> s2[]"<<endl,Print(s2[i]); cout<<"--> S"<<endl; Print(S); } void AddEdge(int fr,int to,int w) { g[fr].push_back(mpr(to,w)); } struct Tree { int dp[N],ds[N],fw[N],ct; int lg[N<<1],rq[N<<1][M],pow2[M]; void DFS(int u,int fa,int w) { fw[u]=++ct,dp[u]=dp[fa]+1,rq[ct][0]=u,ds[u]=w; for(int i=0,v;i<(int)g[u].size();i++) if((v=g[u][i].first)!=fa) DFS(v,u,w+g[u][i].second),rq[++ct][0]=u; } void init() { DFS(1,1,0); pow2[0]=1;for(int i=1;i<M;i++) pow2[i]=pow2[i-1]<<1; lg[0]=-1;for(int i=1;i<=ct;i++) lg[i]=lg[i>>1]+1; for(int j=1;j<M;j++) for(int i=1;i<=ct;i++) if(i+pow2[j]-1<=ct){ int u=rq[i][j-1],v=rq[i+pow2[j-1]][j-1]; if(dp[u]<dp[v]) rq[i][j]=u;else rq[i][j]=v; } } int Dis(int u,int v) { if(fw[u]>fw[v]) swap(u,v); int lg2=lg[fw[v]-fw[u]+1]; int lca=dp[rq[fw[u]][lg2]]<dp[rq[fw[v]-pow2[lg2]+1][lg2]] ? rq[fw[u]][lg2] : rq[fw[v]-pow2[lg2]+1][lg2]; return ds[u]+ds[v]-2*ds[lca]; } }qt; int dis(int u,int v) { return qt.Dis(u,v); } void GetRoot(int u,int fa,int nn) { sz[u]=1,t[u]=0; for(int i=0,v;i<(int)g[u].size();i++) if((v=g[u][i].first)!=fa && !ud[v]) GetRoot(v,u,nn),sz[u]+=sz[v],t[u]=max(t[u],sz[v]); t[u]=max(t[u],nn-sz[u]); if(t[u]<t[rt]) rt=u; } void GetDis(int u,int fa,int ff,int spf) { if(spf) s1[ff].insert(dis(u,spf)); for(int i=0,v;i<(int)g[u].size();i++) if((v=g[u][i].first)!=fa && !ud[v]) GetDis(v,u,ff,spf); } pr Getv(int x) { if(s2[x].size()<2) return mpr(-1,-1); else return mpr((*s2[x].begin()).first+(*(++s2[x].begin())).first,x); } void GetAns(int u,int nn) { ud[u]=1; if(frt[u]) s1[u].insert(dis(u,frt[u]));s2[u].insert(mpr(0,u)); for(int i=0,v;i<(int)g[u].size();i++) if(!ud[v=g[u][i].first]) { GetDis(v,u,u,frt[u]); } for(int i=0,v,ss;i<(int)g[u].size();i++) if(!ud[v=g[u][i].first]) { rt=0,ss=sz[u]>sz[v]?sz[v]:nn-sz[u]; GetRoot(v,v,ss),frt[rt]=u,v=rt,GetAns(rt,ss); s2[u].insert(mpr(*s1[v].begin(),v)); } S.insert(Getv(u)); } //S All //s1 son->father'sfather //s2 sonmax void Modify(int x) { if(cl[x]) cw++;else cw--; vector< int > tmp; for(int i=x;i;i=frt[i]){ tmp.push_back(i); } // for(int i=0;i<(int)tmp.size();i++) cout<<tmp[i]<<" ";cout<<endl; if(cl[x]) { for(int i=0;i<(int)tmp.size();i++) S.erase(Getv(tmp[i])); for(int i=0;i<(int)tmp.size();i++) { // if(!i) s2[tmp[i]].erase(mpr(0,tmp[i])); // else if(i && !s1[tmp[i-1]].empty()) s2[tmp[i]].erase(mpr(*s1[tmp[i-1]].begin(),tmp[i-1])); } for(int i=0;i<(int)tmp.size();i++) s1[tmp[i]].insert(dis(x,frt[tmp[i]])); for(int i=0;i<(int)tmp.size();i++) { if(!i) s2[tmp[i]].insert(mpr(0,tmp[i])); else s2[tmp[i]].insert(mpr(*s1[tmp[i-1]].begin(),tmp[i-1])); } for(int i=0;i<(int)tmp.size();i++) S.insert(Getv(tmp[i])); }else { for(int i=0;i<(int)tmp.size();i++) S.erase(Getv(tmp[i])); // cout<<"--> S"<<endl;Print(S); for(int i=0;i<(int)tmp.size();i++) { if(!i) s2[tmp[i]].erase(mpr(0,tmp[i])); else s2[tmp[i]].erase(mpr(*s1[tmp[i-1]].begin(),tmp[i-1])); } // cout<<"--> s2[1]"<<endl;Print(s2[1]); // cout<<"--> s2[3]"<<endl;Print(s2[3]); for(int i=0;i<(int)tmp.size();i++) if(frt[tmp[i]]) s1[tmp[i]].erase(s1[tmp[i]].find(dis(x,frt[tmp[i]]))); for(int i=0;i<(int)tmp.size();i++) { // if(!i) s2[tmp[i]].insert(mpr(0,tmp[i])); // else if(i && !s1[tmp[i-1]].empty()) s2[tmp[i]].insert(mpr(*s1[tmp[i-1]].begin(),tmp[i-1])); } // cout<<"--> s2[1]"<<endl;Print(s2[1]); for(int i=0;i<(int)tmp.size();i++) S.insert(Getv(tmp[i])); }cl[x]^=1; } void init() { cw=n=in(); for(int i=1,u,v,w;i<n;i++) u=in(),v=in(),w=1,AddEdge(u,v,w),AddEdge(v,u,w); // for(int i=1,u,v,w;i<n;i++) u=in(),v=in(),w=in(),AddEdge(u,v,w),AddEdge(v,u,w); qt.init(); t[0]=N; GetRoot(1,1,n); GetAns(rt,n); } int main() { // freopen("in.in","r",stdin); init(); // SuperPrint(); // Print(S); for(int q=in();q--;) { // cout<<"QAQ"<<endl<<endl; if(getc()=='C') { int x=in();Modify(x); // cout<<"--> S"<<endl;Print(S); // cout<<"--> s1[3]"<<endl;Print(s1[3]); // cout<<"--> s2[3]"<<endl;Print(s2[3]); // SuperPrint(); }else { if(!cw) puts("-1"); else if(cw==1) puts("0"); else printf("%d\n",(*S.begin()).first); } } return 0; }