https://www.lydsy.com/JudgeOnline/problem.php?id=1095
动态点分治
其实就是做点分治时把当前找出来的重心向上一次找到的重心连边,
这样可以是重构后的树高为log的。
重构后的数称为点分树。
构造出点分树,
每个节点开两个堆分别维护子树到它的所有链和他的子树到父分治节点的所有链。
再开一个全局堆维护每个节点的最大答案。
老年选手表示已经码不动数据结构,debug 2hours,QWQ。
#include<cstdio> #include<algorithm> #include<queue> #include<iostream> #define re register #define rep(i,s,t) for(register int i=s;i<=t;++i) #define _rep(i,s,t) for(register int i=s;i>=t;--i) #define Rep(i,s,t) for(register int i=s;i<t;++i) #define go(x) for(register int e=las[x];e;e=nxt[e]) using namespace std; namespace IO{ #define gc getchar() #define pc(x) putchar(x) template<typename T>inline void read(T &x){ x=0;int f=1;char ch=gc;while(ch>'9'||ch<'0'){if(ch=='-')f=-1;ch=gc;} while(ch>='0'&&ch<='9')x=(x<<3)+(x<<1)+ch-'0',ch=gc;x*=f;return; } template<typename T>inline void write(T x=0){ T wr[51];wr[0]=0;if(x<0)pc('-'),x=-x;if(!x)pc(48); while(x)wr[++wr[0]]=x%10,x/=10;while(wr[0])pc(48+wr[wr[0]--]);return; } } using IO::read; using IO::write; #define gi(x) read(x) #define gii(x,y) read(x),read(y) #define giii(x,y,z) read(x),read(y),read(z) const int N=2e5+11,inf=1<<30; int n,m,tot,x,y,sum,rt; int nxt[N],las[N],to[N],up[N][18],dep[N]; int sz[N],mx[N],fa[N]; bool vis[N],light[N]; struct heap{ priority_queue<int>A,B; inline void push(int x){ A.push(x); } inline void erase(int x){ B.push(x); } inline int top(){ for(;B.size()&&A.top()==B.top();) A.pop(),B.pop(); if(A.size()) return A.top(); return 0; } inline void pop(){ for(;B.size()&&A.top()==B.top();) A.pop(),B.pop(); if(A.size()) A.pop(); } inline int sec(){ re int tmp=top(); pop(); re int ret=top(); push(tmp); return ret; } inline int size(){ return A.size()-B.size(); } }c[N>>1],f[N>>1],ans; inline void ins(heap &s){ //if(s.size()>1) // printf("ins:%d %d ",s.top(),s.sec()); if(s.size()>1) ans.push(s.top()+s.sec()); } inline void del(heap &s){ //if(s.size()>1) // printf("del:%d %d ",s.top(),s.sec()); if(s.size()>1) ans.erase(s.top()+s.sec()); } inline void add(int x,int y){ nxt[++tot]=las[x],las[x]=tot,to[tot]=y; } inline void dfs(int x,int anc){ up[x][0]=anc; rep(i,1,17) up[x][i]=up[up[x][i-1]][i-1]; go(x){ if(to[e]==anc)continue; dep[to[e]]=dep[x]+1; dfs(to[e],x); } } inline int lca(int x,int y){ if(dep[x]<dep[y])swap(x,y); int t=dep[x]-dep[y]; _rep(i,17,0) if(t>>i&1) x=up[x][i]; if(x==y) return x; _rep(i,17,0) if(up[x][i]!=up[y][i]) x=up[x][i],y=up[y][i]; return up[x][0]; } inline int dis(int x,int y){ return dep[x]+dep[y]-2*dep[lca(x,y)]; } inline void findrt(int x,int anc){ sz[x]=1,mx[x]=0; go(x){ if(vis[to[e]]||to[e]==anc)continue; findrt(to[e],x); sz[x]+=sz[to[e]]; mx[x]=max(mx[x],sz[to[e]]); } mx[x]=max(mx[x],sum-sz[x]); if(mx[x]<mx[rt]) rt=x; } inline void work(int x,int anc,int R){ //printf("%d %d %d ",x,anc,R); f[rt].push(dis(x,R)); go(x){ if(to[e]==anc||vis[to[e]])continue; work(to[e],x,R); } } inline void build_tree(int x,int anc){ fa[x]=anc,vis[x]=1,c[x].push(0),work(x,0,anc); //printf("%d %d ",x,anc); int v; go(x){ if(vis[to[e]])continue; rt=0,mx[0]=inf,sum=sz[to[e]], findrt(to[e],x),v=rt,build_tree(rt,x); c[x].push(f[v].top()); } ins(c[x]); } inline void on(int x){ del(c[x]),c[x].erase(0),ins(c[x]); for(re int i=x;i;i=fa[i]){ del(c[fa[i]]); if(f[i].size()) c[fa[i]].erase(f[i].top()); f[i].erase(dis(x,fa[i])); if(f[i].size()) c[fa[i]].push(f[i].top()); ins(c[fa[i]]); } } inline void off(int x){ del(c[x]),c[x].push(0),ins(c[x]); for(re int i=x;i;i=fa[i]){ del(c[fa[i]]); if(f[i].size()) c[fa[i]].erase(f[i].top()); f[i].push(dis(x,fa[i])); if(f[i].size()) c[fa[i]].push(f[i].top()); ins(c[fa[i]]); } } int main(){ gi(n); rep(i,2,n){ gii(x,y); add(x,y),add(y,x); } dfs(1,0),mx[0]=inf,rt=0,sum=n, findrt(1,0),build_tree(rt,0); int num=n,q;char ch[10]; gi(q); for(;q--;){ scanf("%s",ch); if(ch[0]=='C'){ gi(x); if(light[x]) off(x),++num; else on(x),--num; light[x]^=1; } else printf("%d ",num<=1?num-1:ans.top()); } return 0; }