bzoj 1095
首先仍然是点对之间的问题,让我们考虑点分
由于带修改,所以考虑动态点分治
所谓动态点分治,就是在操作之前先模拟一遍点分治的过程构造出一棵新的树,我们称这棵树为点分树,由于这棵树树高是对数级别的,所以修改的时候可以在一条树链上暴力修改
然后考虑本题怎么维护:
首先我们考虑答案如何统计:在统计答案时,我们找出每个节点向其所有子树中最大的距离,然后计算这些最大深度的最大值+次大值,然后放进一个堆里维护即可
为什么要放进堆里维护?
因为还可能需要插入或删除嘛!
这样的话,我们考虑怎么维护答案
首先我们需要记录以一个点为根节点的子树中到这个点最深的深度,这一点比较好维护
然后我们还需要记录以一个点为根节点子树中向上更新的最深的深度,这一点也比较容易维护
(注意我们现在的树是点分树,但深度讨论的是原来的树!因此不能简单地传递!)
接下来就是堆的删除和修改了
有个小trick:开两个堆,如果需要删除的话推到另一个堆里,在查询时如果两堆堆顶相等就一起弹掉
需要卡常,求LCA不妨用欧拉序
贴代码:
// luogu-judger-enable-o2 #include <cstdio> #include <cmath> #include <cstring> #include <algorithm> #include <queue> #define uint unsigned int using namespace std; struct Edge { uint nxt; uint to; }edge[200005]; struct Heap { priority_queue <uint> Q1,Q2; void push(uint x){Q1.push(x);} void del(uint x){Q2.push(x);} uint top() { while(!Q1.empty()&&!Q2.empty()&&Q1.top()==Q2.top())Q1.pop(),Q2.pop(); if(!Q1.empty())return Q1.top(); else return -1; } void pop() { while(!Q1.empty()&&!Q2.empty()&&Q1.top()==Q2.top())Q1.pop(),Q2.pop(); if(!Q1.empty())Q1.pop(); } bool empty(){return Q1.size()-Q2.size()==0;} uint size(){return Q1.size()-Q2.size();} uint sec() { if(Q1.size()-Q2.size()<=1)return -1; uint t=top();pop(); uint ret=top();push(t); return ret; } }Q[100005][2],re; uint head[100005]; uint siz[100005],maxp[100005]; uint pre[100005],vis[100005]; uint sit[100005]; uint ttop[100005]; uint lg2[500005]; uint dep[100005]; uint dfn[100005]; uint rmq[500005][22]; uint s,rt; uint t=0; uint cnt=1; uint n,m,s_lig; inline void add(uint l,uint r) { edge[cnt].nxt=head[l]; edge[cnt].to=r; head[l]=cnt++; } void dfs(uint x,uint fx) { dep[x]=dep[fx]+1,dfn[x]=++t; rmq[t][0]=x; for(register uint i=head[x];i;i=edge[i].nxt) { uint to=edge[i].to; if(to==fx)continue; dfs(to,x); rmq[++t][0]=x; } } /*void redfs(uint x,uint topx,uint fx) { ttop[x]=topx; if(son[x])redfs(son[x],topx,x); for(register uint i=head[x];i;i=edge[i].nxt) { uint to=edge[i].to; if(to==fx||to==son[x])continue; redfs(to,to,x); } }*/ void get_f() { for(register uint j=1;j<=17;++j) { for(register uint i=1;i+(1<<j)-1<=t;++i) { rmq[i][j]=dep[rmq[i][j-1]]<dep[rmq[i+(1<<(j-1))][j-1]]?rmq[i][j-1]:rmq[i+(1<<(j-1))][j-1]; } } for(register uint i=2;i<=t;i++)lg2[i]=lg2[i>>1]+1; } inline uint LCA(uint x,uint y) { int l=dfn[x],r=dfn[y]; if(l>r)swap(l,r); int lg=lg2[r-l+1]; return dep[rmq[l][lg]]<dep[rmq[r-(1<<lg)+1][lg]]?rmq[l][lg]:rmq[r-(1<<lg)+1][lg]; } inline uint get_dis(uint x,uint y) { return dep[x]+dep[y]-2*dep[LCA(x,y)]; } void get_rt(uint x,uint fx) { siz[x]=1,maxp[x]=0; for(register uint i=head[x];i;i=edge[i].nxt) { uint to=edge[i].to; if(to==fx||vis[to])continue; get_rt(to,x); siz[x]+=siz[to]; maxp[x]=max(maxp[x],siz[to]); } maxp[x]=max(maxp[x],s-siz[x]); if(maxp[x]<maxp[rt])rt=x; } void solve(uint x) { vis[x]=1; for(register uint i=head[x];i;i=edge[i].nxt) { int to=edge[i].to; if(vis[to])continue; s=siz[to],rt=0; get_rt(to,0); pre[rt]=x,solve(rt); } } void ins(uint x) { if(Q[x][1].size()>=2)re.push(Q[x][1].top()+Q[x][1].sec()); } void del(uint x) { if(Q[x][1].size()>=2)re.del(Q[x][1].top()+Q[x][1].sec()); } void turn_off(uint x) { del(x),Q[x][1].push(0),ins(x); s_lig--; for(uint i=x,pi=pre[x];pi;i=pi,pi=pre[i]) { del(pi); if(!Q[i][0].empty())Q[pi][1].del(Q[i][0].top()); Q[i][0].push(get_dis(x,pi)); Q[pi][1].push(Q[i][0].top()); ins(pi); } } void turn_on(uint x) { del(x),Q[x][1].del(0),ins(x); s_lig++; for(uint i=x,pi=pre[x];pi;i=pi,pi=pre[i]) { del(pi); if(!Q[i][0].empty())Q[pi][1].del(Q[i][0].top()); Q[i][0].del(get_dis(x,pi)); if(!Q[i][0].empty())Q[pi][1].push(Q[i][0].top()); ins(pi); } } inline uint read() { uint f=1,x=0;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=1;ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} return x*f; } int main() { n=read(); for(register uint i=1;i<n;++i) { uint x=read(),y=read(); add(x,y),add(y,x); } rt=0,s=n,maxp[0]=0x3f3f3f3f; dfs(1,1),get_f(),get_rt(1,0),solve(rt); for(register uint i=1;i<=n;++i)turn_off(i); s_lig=0; m=read(); while(m--) { char typ=getchar(); while(typ!='C'&&typ!='G')typ=getchar(); if(typ=='C') { uint x=read(); if(sit[x])turn_off(x); else turn_on(x); sit[x]^=1; }else { if(s_lig==n)printf("-1\n"); else if(s_lig==n-1)printf("0\n"); else printf("%u\n",re.top()); } } return 0; }