题解:
SDOI SD题。
LCT维护线段树,
线段树维护dfs序。
由于每次修改只是从根到x,我们可以将它理解为LCT的access操作。
然后轻重链信息发生变化时,在线段树上改一下就好了。
LCTaccess板子敲错导致自己做自己爷爷。
代码:
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; #define N 100050 inline int rd() { int f=1,c=0;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){c=10*c+ch-'0';ch=getchar();} return f*c; } int n,m,hed[N],cnt; struct EG { int to,nxt; }e[2*N]; void ae(int f,int t) { e[++cnt].to = t; e[cnt].nxt = hed[f]; hed[f] = cnt; } int pla[N],dep[N]; struct segtree { int mx[N<<2],tag[N<<2]; void update(int u) { mx[u] = max(mx[u<<1],mx[u<<1|1]); } void add(int u,int d) { tag[u]+=d; mx[u]+=d; } void pushdown(int u) { if(tag[u]) { add(u<<1,tag[u]); add(u<<1|1,tag[u]); tag[u] = 0; } } void build(int l,int r,int u) { if(l==r) { mx[u] = dep[pla[l]]; return ; } int mid = (l+r)>>1; build(l,mid,u<<1); build(mid+1,r,u<<1|1); update(u); } void insert(int l,int r,int u,int ql,int qr,int d) { if(l==ql&&r==qr) { add(u,d); return ; } pushdown(u); int mid = (l+r)>>1; if(qr<=mid)insert(l,mid,u<<1,ql,qr,d); else if(ql>mid)insert(mid+1,r,u<<1|1,ql,qr,d); else insert(l,mid,u<<1,ql,mid,d),insert(mid+1,r,u<<1|1,mid+1,qr,d); update(u); } int query(int l,int r,int u,int ql,int qr) { if(l==ql&&r==qr)return mx[u]; pushdown(u); int mid = (l+r)>>1; if(qr<=mid)return query(l,mid,u<<1,ql,qr); else if(ql>mid)return query(mid+1,r,u<<1|1,ql,qr); else return max(query(l,mid,u<<1,ql,mid),query(mid+1,r,u<<1|1,mid+1,qr)); } int ask(int l,int r,int u,int qx) { if(l==r)return mx[u]; pushdown(u); int mid = (l+r)>>1; if(qx<=mid)return ask(l,mid,u<<1,qx); else return ask(mid+1,r,u<<1|1,qx); } }tr1; int tin[N],tout[N],tim; struct LCT { int fa[N],ch[N][2]; bool rt[N]; void rotate(int x) { int y = fa[x],z = fa[y],k = (ch[y][1]==x); if(rt[y])rt[x]=1,rt[y]=0; else ch[z][ch[z][1]==y]=x; fa[x] = z; ch[y][k] = ch[x][!k],fa[ch[x][!k]] = y; ch[x][!k] = y,fa[y] = x; } void splay(int x) { while(!rt[x]) { int y = fa[x],z = fa[y]; if(!rt[y]) (ch[y][1]==x)^(ch[z][1]==y)?rotate(x):rotate(y); rotate(x); } } int findroot(int x) { while(ch[x][0])x=ch[x][0]; return x; } void access(int x) { int y = 0,v; while(x) { splay(x); if(ch[x][1]) { v = findroot(ch[x][1]); tr1.insert(1,n,1,tin[v],tout[v],1); } if(y) { v = findroot(y); tr1.insert(1,n,1,tin[v],tout[v],-1); } rt[y]=0,rt[ch[x][1]]=1; ch[x][1] = y; y=x,x=fa[x]; } } }tr2; int ff[N],son[N],siz[N],top[N]; void dfs1(int u,int f) { siz[u]=1; ff[u]=f; tr2.fa[u]=f; tr2.rt[u]=1; dep[u]=dep[f]+1; for(int j=hed[u];j;j=e[j].nxt) { int to = e[j].to; if(to==f)continue; dfs1(to,u); siz[u]+=siz[to]; if(siz[to]>siz[son[u]])son[u]=to; } } void dfs2(int u,int tp) { top[u] = tp; tin[u] = ++tim;pla[tim] = u; if(son[u]) { dfs2(son[u],tp); for(int j=hed[u];j;j=e[j].nxt) { int to = e[j].to; if(to==ff[u]||to==son[u])continue; dfs2(to,to); } } tout[u]=tim; } int get_lca(int x,int y) { while(top[x]!=top[y]) { if(dep[top[x]]<dep[top[y]])swap(x,y); x = ff[top[x]]; } return dep[x]<dep[y]?x:y; } int main() { // freopen("1.in","r",stdin); n = rd(),m = rd(); for(int f,t,i=1;i<n;i++) { f=rd(),t=rd(); ae(f,t),ae(t,f); } dfs1(1,0); dfs2(1,1); tr1.build(1,n,1); for(int opt,x,y,i=1;i<=m;i++) { opt = rd(),x = rd(); if(opt==1) { tr2.access(x); }else if(opt==2) { y = rd(); int k1 = tr1.ask(1,n,1,tin[x]); int k2 = tr1.ask(1,n,1,tin[y]); int lca = get_lca(x,y); int k3 = tr1.ask(1,n,1,tin[lca]); printf("%d ",k1+k2-2*k3+1); }else { printf("%d ",tr1.query(1,n,1,tin[x],tout[x])); } } return 0; }