LuoguP4271 [USACO18FEB]New Barns P 树的直径+LCT
结论:如果边权非负,则距离树上一个点最远的点一定是直径端点之一.
由此可得我们只需维护树的直径就行.
这种维护方法的局限性在于不可以有删边操作.
假如合并两个连通块 A,B, 直径端点分别为 $x_{0},x_{1},x_{2},x_{3}$,新树直径的端点一定是在 4 个点中的两个.
那就两两取 max,然后求直径端点距离 x 的距离用 LCT 中的 split 就行了.
code:
#include <cstdio> #include <algorithm> #define N 100008 #define ls s[x].ch[0] #define rs s[x].ch[1] #define setIO(s) freopen(s".in","r",stdin) using namespace std; struct data { int rev,f,ch[2],si; }s[N]; int p[N],ax[N],bx[N],w[N],sta[N]; int get(int x) { return s[s[x].f].ch[1]==x; } int isr(int x) { return s[s[x].f].ch[0]!=x&&s[s[x].f].ch[1]!=x; } void pushup(int x) { s[x].si=s[ls].si+s[rs].si+1; } void rotate(int x) { int old=s[x].f,fold=s[old].f,which=get(x); if(!isr(old)) s[fold].ch[s[fold].ch[1]==old]=x; s[old].ch[which]=s[x].ch[which^1]; if(s[old].ch[which]) s[s[old].ch[which]].f=old; s[x].ch[which^1]=old,s[old].f=x,s[x].f=fold; pushup(old),pushup(x); } void mark(int x) { swap(ls,rs),s[x].rev^=1; } void pushdown(int x) { if(s[x].rev) { if(ls) mark(ls); if(rs) mark(rs); s[x].rev=0; } } void splay(int x) { int v=0,u=x,fa; for(sta[++v]=u;!isr(u);u=s[u].f) sta[++v]=s[u].f; for(;v;--v) pushdown(sta[v]); for(u=s[u].f;(fa=s[x].f)!=u;rotate(x)) if(s[fa].f!=u) rotate(get(fa)==get(x)?fa:x); } void access(int x) { for(int y=0;x;y=x,x=s[x].f) splay(x),rs=y,pushup(x); } void makert(int x) { access(x),splay(x),mark(x); } void link(int x,int y) { makert(x),s[x].f=y; } void init() { for(int i=0;i<N;++i) { p[i]=i; w[i]=0,ax[i]=bx[i]=i; } } int find(int x) { return p[x]==x?x:p[x]=find(p[x]); } int Dis(int x,int y) { makert(x),access(y),splay(y); return s[y].si-1; } struct node { int x,y; node(int x=0,int y=0):x(x),y(y){} }ma[10]; void merge(int x,int y) { int oa=find(x),ob=find(y); ma[1]=node(ax[oa],Dis(ax[oa],x)); ma[2]=node(bx[oa],Dis(bx[oa],x)); ma[3]=node(ax[ob],Dis(ax[ob],y)); ma[4]=node(bx[ob],Dis(bx[ob],y)); int a=0,b=0,c=0; for(int i=1;i<=2;++i) for(int j=3;j<=4;++j) if(ma[i].y+ma[j].y+1>c) c=ma[i].y+ma[j].y+1,a=i,b=j; if(c<max(w[oa],w[ob])) { if(w[ob]>w[oa]) p[oa]=ob; else p[ob]=oa; } else { p[oa]=ob; w[ob]=c; ax[ob]=ma[a].x; bx[ob]=ma[b].x; } link(x,y); } int main() { // setIO("input"); init(); int q,x,y,z,n=0; char op[10]; scanf("%d",&q); for(int i=1;i<=q;++i) { scanf("%s",op); if(op[0]=='B') { scanf("%d",&x); s[++n].si=1; if(x!=-1) merge(n,x); } if(op[0]=='Q') { scanf("%d",&x),y=find(x); int a=ax[y],b=bx[y]; printf("%d\n",max(Dis(x,a),Dis(x,b))); } } return 0; }