Description
Bob有一棵n个点的有根树,其中1号点是根节点。Bob在每个点上涂了颜色,并且每个点上的颜色不同。定义一条路
径的权值是:这条路径上的点(包括起点和终点)共有多少种不同的颜色。Bob可能会进行这几种操作:
1 x:
把点x到根节点的路径上所有的点染上一种没有用过的新颜色。
2 x y:
求x到y的路径的权值。
3 x y:
在以x为根的子树中选择一个点,使得这个点到根节点的路径权值最大,求最大权值。
Bob一共会进行m次操作
Input
第一行两个数n,m。
接下来n-1行,每行两个数a,b,表示a与b之间有一条边。
接下来m行,表示操作,格式见题目描述
1<=n,m<=100000
Output
每当出现2,3操作,输出一行。
如果是2操作,输出一个数表示路径的权值
如果是3操作,输出一个数表示权值的最大值
由于染色都是从根开始的一条路径,可以发现:
操作1就是无换根操作的lct的access,操作2是查询给定路径经过lct中几条虚边,操作3是查询子树内到根的最大虚边条数
lct每次access均摊修改O(logn)条边的虚实,因此可以维护原树的lct方便操作1
树链剖分+树状数组维护路径上虚边条数
线段树维护dfs序,区间内点到根路径上最大虚边条数
于是每次修改边的类型时,对应在树状数组上单点修改,线段树上区间加
总复杂度O(mlog2(n))
#include<cstdio> const int N=100007; char buf[N*100],*ptr=buf-1; int _(){ int x=0,c=*++ptr; while(c<48)c=*++ptr; while(c>47)x=x*10+c-48,c=*++ptr; return x; } int n,m,es[N*2],enx[N*2],e0[N],ep=2,dw[N]; int _l,_r,_a; int max(int a,int b){return a>b?a:b;} namespace SGT{ struct node{ node*lc,*rc; int L,R,M; int mx,a; void _add(int x){ mx+=x;a+=x; } void dn(){ if(a){ lc->_add(a); rc->_add(a); a=0; } } void up(){ mx=max(lc->mx,rc->mx); } void add(){ if(_l<=L&&R<=_r){ _add(_a); return; } dn(); if(_l<=M)lc->add(); if(_r>M)rc->add(); up(); } int gmx(){ if(_l<=L&&R<=_r)return mx; dn(); if(_r<=M)return lc->gmx(); if(_l>M)return rc->gmx(); return max(lc->gmx(),rc->gmx()); } }ns[N*2],*np=ns,*rt; node*build(int L,int R){ node*w=np++; w->L=L;w->R=R; if(L<R){ int M=w->M=L+R>>1; w->lc=build(L,M); w->rc=build(M+1,R); } return w; } } namespace BIT{ int f[N]; void inc(int w,int x){ for(;w<=n;w+=w&-w)f[w]+=x; } int sum(int w){ int s=0; for(;w;w-=w&-w)s+=f[w]; return s; } } namespace HLD{ using namespace SGT; using namespace BIT; int fa[N],sz[N],son[N],dep[N],top[N],id[N],id2[N],idp=0; void f1(int w,int pa){ dep[w]=dep[fa[w]=pa]+1; sz[w]=1; for(int i=e0[w];i;i=enx[i]){ int u=es[i]; if(u!=pa){ f1(u,w); sz[w]+=sz[u]; if(sz[u]>sz[son[w]])son[w]=u; } } } void f2(int w,int tp){ top[w]=tp; id[w]=++idp; if(son[w])f2(son[w],tp); for(int i=e0[w];i;i=enx[i]){ int u=es[i]; if(u!=fa[w]&&u!=son[w])f2(u,u); } id2[w]=idp; } int lca(int x,int y){ int a=top[x],b=top[y],s=1; while(a!=b){ if(dep[a]>dep[b]){ s+=BIT::sum(id[x])-BIT::sum(id[a]-1); x=fa[a],a=top[x]; }else{ s+=BIT::sum(id[y])-BIT::sum(id[b]-1); y=fa[b],b=top[y]; } } if(dep[x]>dep[y])s+=BIT::sum(id[x])-BIT::sum(id[y]); if(dep[x]<dep[y])s+=BIT::sum(id[y])-BIT::sum(id[x]); return s; } void init(){ f1(1,0);f2(1,1); rt=build(1,n); for(int i=2;i<=n;++i){ inc(id[i],1); _l=id[i],_r=id2[i],_a=1; rt->add(); } } int query(int x){ _l=id[x],_r=id2[x]; return rt->gmx()+1; } void setdw(int x,int y){ if(dw[x]){ inc(id[dw[x]],1); _l=id[dw[x]],_r=id2[dw[x]],_a=1; rt->add(); } if(dw[x]=y){ inc(id[y],-1); _l=id[y],_r=id2[y],_a=-1; rt->add(); } } } namespace LCT{ #define lc ch][0 #define rc ch][1 #define fa ch][2 int ch[N][4]; bool nrt(int x){return x==x[fa][lc]||x==x[fa][rc];} void rot(int x){ int f=x[fa],g=f[fa],d=(x!=f[lc]); if(nrt(f))g[ch][g[lc]!=f]=x; x[fa]=g; (f[ch][d]=x[ch][d^1])[fa]=f; (x[ch][d^1]=f)[fa]=x; } void sp(int x){ while(nrt(x)){ int f=x[fa]; if(nrt(f))rot((x==f[lc])==(f==f[fa][lc])?f:x); rot(x); } } int gl(int x){ while(x[lc])x=x[lc]; sp(x); return x; } void acs(int x){ for(int y=0;x;sp(x),HLD::setdw(x,y),x[rc]=y,y=gl(x),x=y[fa]); } #undef lc #undef rc #undef fa } int main(){ fread(buf,1,sizeof(buf),stdin)[buf]=0; n=_();m=_(); for(int i=1,a,b;i<n;++i){ a=_();b=_(); es[ep]=b;enx[ep]=e0[a];e0[a]=ep++; es[ep]=a;enx[ep]=e0[b];e0[b]=ep++; } HLD::init(); for(int i=2;i<=n;++i)LCT::ch[i][2]=HLD::fa[i]; for(int i=0,o,a,b;i<m;++i){ o=_(); if(o==1){ a=_(); LCT::acs(a); }else if(o==2){ a=_();b=_(); printf("%d\n",HLD::lca(a,b)); }else{ a=_(); printf("%d\n",HLD::query(a)); } } return 0; }