Luogu P3703 [SDOI2017]树点涂色
用LCT中每一个Splay维护颜色相同的点集,则从一个点到根节点的轻边的条数就是这个点的到根的权值。至于路径查询的搞个差分就好,用树剖实现。
至于为什么可以直接这样查,是因为LCT里面涉及子树的权值变化只有access函数。在splay中的子树的切换是属于实链中的变化,对权值没有影响。
所以这题其实就是个裸树剖+LCT

#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;

#define R register
#define LL long long
const int inf = 0x3f3f3f3f;
const int MAXN = 1e5 + 10;

inline int read() {
	char a = getchar(); int x = 0,f = 1;
	for(; a > '9' || a < '0'; a = getchar()) if(a == '-') f = -1;
	for(; a >= '0' && a <= '9' ;a = getchar()) x = x * 10 + a - '0';
	return x * f;
}

namespace Data {
	class SegTree {
		#define ls(x) (x<<1)
		#define rs(x) (x<<1|1)
		private: 
			int tg[MAXN<<2],mx[MAXN<<2];
			inline void update(int x) { mx[x]=max(mx[ls(x)], mx[rs(x)]); }
			inline void get(int x,int k) { tg[x]+=k; mx[x]+=k; }
			inline void pushdown(int x) {
				if(tg[x]) {
					if(ls(x)) get(ls(x),tg[x]);
					if(rs(x)) get(rs(x),tg[x]);
					tg[x]=0;
				}
			}
		public:
			inline void add(int x,int l,int r,int Le,int Ri,int k) {
				if(Le<=l&&r<=Ri) { get(x,k); return ;}
				pushdown(x);
				int mid=l+r;mid>>=1;
				if(Le<=mid) add(ls(x),l,mid,Le,Ri,k);
				if(Ri>mid) add(rs(x),mid+1,r,Le,Ri,k);
				update(x);
			}
			inline int ask(int x,int l,int r,int Le,int Ri) {
				if(Le<=l&&r<=Ri) return mx[x];
				pushdown(x);
				int mid=l+r;mid>>=1;
				int ans=-inf;
				if(Le<=mid) ans=max(ans,ask(ls(x),l,mid,Le,Ri));
				if(Ri>mid) ans=max(ans,ask(rs(x),mid+1,r,Le,Ri));
				update(x);
				return ans;
			}
		#undef ls
		#undef rs
	};
}

using Data::SegTree;

namespace Graph {
	struct Edge { int to,next; } e[MAXN<<1];
	int head[MAXN],cnt;
	inline void add(int x,int y) { e[++cnt]={y,head[x]}; head[x]=cnt; }
	int dep[MAXN],fa[MAXN],siz[MAXN],son[MAXN],top[MAXN],dfn[MAXN],tot;
	inline void dfs1(int x,int fx) {
		dep[x]=dep[fx]+1; fa[x]=fx; siz[x]=1; dfn[x]=++tot;
		for(R int i=head[x];i;i=e[i].next) {
			int y=e[i].to;
			if(y==fx) continue;
			dfs1(y,x);
			siz[x]+=siz[y];
			if(siz[y]>siz[son[x]]) son[x]=y;
		}
	}
	inline void dfs2(int x,int topx) {
		top[x]=topx;
		if(son[x]) dfs2(son[x],topx);
		for(R int i=head[x];i;i=e[i].next) {
			int y=e[i].to;
			if(y==fa[x]||y==son[x]) continue;
			dfs2(y,y);
		}
	}
	inline int lca(int x,int y) {
		while(top[x]!=top[y])
			if(dep[top[x]]>dep[top[y]]) 
				x=fa[top[x]];
			else
				y=fa[top[y]];
		return dep[x]<dep[y]?x:y;
	}
	inline void build() { dfs1(1,0); dfs2(1,1); }
}

using Graph::dfn;
using Graph::lca;
using Graph::build;
using Graph::add;
using Graph::siz;
using Graph::dep;
using Graph::head;
using Graph::e;

int n,m;
SegTree ST;
namespace Link_Cut_Tree {
	class LCT {
		#define ls(x) ch[x][0]
		#define rs(x) ch[x][1]
		private:
			int fa[MAXN],ch[MAXN][2];
		public:
			inline int nroot(int x) { return rs(fa[x])==x||ls(fa[x])==x; }
			inline int get(int x) { return rs(fa[x])==x; }
			inline void rotate(int x) {
				int y=fa[x],z=fa[y],k=get(x),w=ch[x][!k];
				if(nroot(y)) ch[z][get(y)]=x; ch[x][!k]=y; ch[y][k]=w;
				if(w) fa[w]=y; fa[y]=x; fa[x]=z;
			}
			inline void splay(int x) {
				while(nroot(x)) {
					if(nroot(fa[x]))
						rotate(get(x)^get(fa[x])?x:fa[x]);
					rotate(x);				
				}	
			}
			inline int findrt(int x) {
				while(ls(x)) x=ls(x); return x;
			}
			inline void access(int x) {
				for(R int y=0;x;x=fa[y=x]) {
					splay(x);
					if(rs(x)) {
						int rt=findrt(rs(x));
						ST.add(1,1,n,dfn[rt],dfn[rt]+siz[rt]-1,1);
					}
					if(y) {
						int rt=findrt(y);
						ST.add(1,1,n,dfn[rt],dfn[rt]+siz[rt]-1,-1);
					}
					rs(x)=y;
				}
			}
			inline void build(int x,int fx) {
				fa[x]=fx;
				for(R int i=head[x];i;i=e[i].next) {
					int y=e[i].to;
					if(y==fx) continue;
					build(y,x);
				}
			}
		#undef ls
		#undef rs
	};
}

using Link_Cut_Tree::LCT;

LCT T;

int main() {
	n=read(); m=read();
	for(R int i=1;i<n;i++) {
		int x=read(),y=read();
		add(x,y); add(y,x);	
	}
	build();T.build(1,0);
	for(R int i=1;i<=n;i++) ST.add(1,1,n,dfn[i],dfn[i],dep[i]);
	while(m--) {
		int op=read(),x=read(),y;
		if(op==2) y=read();
		if(op==1) T.access(x);
		if(op==2) {
			int Lca=lca(x,y);
			int s1=ST.ask(1,1,n,dfn[x],dfn[x]);
			int s2=ST.ask(1,1,n,dfn[y],dfn[y]);
			int s3=ST.ask(1,1,n,dfn[Lca],dfn[Lca]);
			printf("%d\n",s1+s2-s3*2+1);
		}
		if(op==3) {
			int s=ST.ask(1,1,n,dfn[x],dfn[x]+siz[x]-1);
			printf("%d\n",s);
		}
	}
	return 0;	
}