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操作,输出一个数表示权值的最大值
Sample Input
5 6
1 2
2 3
3 4
3 5
2 4 5
3 3
1 4
2 4 5
1 5
2 4 5
Sample Output
3
4
2
2
题解
把操作一当成lct的access操作,我们认为一个点到根的虚边数量+1为不同颜色种数。
这样我们就可以在access操作时修改需要修改的点。
如果一个点与其父亲的边变成虚边,则其及其子树到根的权值+1。
如果一个点与其父亲的边变成实边,则其及其子树到根的权值-1。
与子树有关的操作,我们可以用dfs序+线段树维护。
对于操作2,类似于lca求两点间的距离,d[a]+d[b]-d[lca(a,b)]+1
细节:access操作修改时,时修改splay中最左边点的子树。
代码
#include<bits/stdc++.h>
#define ll long long
#define inf 1000000000
#define mod 201314
using namespace std;
const int N=100005;
inline int read()
{
int x=0,f=1;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 Head[N],ret[N<<1],Next[N<<1],tot;
int l[N],r[N],tim;
int mx[N<<2],sum[N<<2],lazy[N<<2];
int dep[N],fa[N],f[N][18],a[N];
int c[N][2],up[N];
int n,m;
inline void ins(int u,int v){ret[++tot]=v;Next[tot]=Head[u];Head[u]=tot;}
void dfs(int u)
{
l[u]=++tim;a[tim]=dep[u];
for (int i=1;i<=17;i++) f[u][i]=f[f[u][i-1]][i-1];
for (int i=Head[u];i;i=Next[i])
{
if (ret[i]==f[u][0]) continue;
fa[ret[i]]=f[ret[i]][0]=u;
dep[ret[i]]=dep[u]+1;
dfs(ret[i]);
}
r[u]=tim;
}
inline void pushdown(int k,int l,int r)
{
if (l==r) return;
mx[k<<1]+=lazy[k];mx[k<<1|1]+=lazy[k];
lazy[k<<1]+=lazy[k];lazy[k<<1|1]+=lazy[k];
lazy[k]=0;
}
int query(int k,int l,int r,int x)
{
if (lazy[k]) pushdown(k,l,r);
if (l==r) return sum[k]+lazy[k];
int mid=(l+r)>>1;
if (x<=mid) return query(k<<1,l,mid,x);
else return query(k<<1|1,mid+1,r,x);
}
int MX(int k,int l,int r,int x,int y)
{
if (lazy[k]) pushdown(k,l,r);
if (l==x&&r==y) return mx[k];
int mid=(l+r)>>1;
if (y<=mid) return MX(k<<1,l,mid,x,y);
else if (x>mid) return MX(k<<1|1,mid+1,r,x,y);
else return max(MX(k<<1,l,mid,x,mid),MX(k<<1|1,mid+1,r,mid+1,y));
}
void modify(int k,int l,int r,int x,int y,int z)
{
if (lazy[k]) pushdown(k,l,r);
if (l==x&&r==y){mx[k]+=z;lazy[k]+=z;return;}
int mid=(l+r)>>1;
if (y<=mid) modify(k<<1,l,mid,x,y,z);
else if (x>mid) modify(k<<1|1,mid+1,r,x,y,z);
else modify(k<<1,l,mid,x,mid,z),modify(k<<1|1,mid+1,r,mid+1,y,z);
mx[k]=max(mx[k<<1],mx[k<<1|1]);
}
void build(int k,int l,int r)
{
if (l==r){mx[k]=a[l];sum[k]=a[l];return;}
int mid=(l+r)>>1;
build(k<<1,l,mid);build(k<<1|1,mid+1,r);
mx[k]=max(mx[k<<1],mx[k<<1|1]);
}
bool isroot(int x){return c[fa[x]][0]!=x&&c[fa[x]][1]!=x;}
inline void update(int x)
{
int l=c[x][0];
if (l) up[x]=up[l];else up[x]=x;
}
inline void rotate(int x)
{
int y=fa[x],z=fa[y],l,r;
if (c[y][0]==x)l=0;else l=1;r=l^1;
if (!isroot(y))
{
if (c[z][0]==y) c[z][0]=x;else c[z][1]=x;
}
fa[x]=z;fa[y]=x;c[y][l]=c[x][r];fa[c[x][r]]=y;c[x][r]=y;
update(y);update(x);
}
void splay(int x)
{
while (!isroot(x))
{
int y=fa[x],z=fa[y];
if (!isroot(y))
{
if (c[z][0]==y^c[y][0]==x) rotate(x);else rotate(y);
}
rotate(x);
}
}
void access(int x)
{
int t=0;
while (x)
{
splay(x);
if (c[x][1]) modify(1,1,n,l[up[c[x][1]]],r[up[c[x][1]]],1);
if (t) modify(1,1,n,l[up[t]],r[up[t]],-1);
c[x][1]=t;
update(x);
t=x;
x=fa[x];
}
}
inline int lca(int a,int b)
{
if (dep[a]<dep[b]) swap(a,b);
for (int i=17;i>=0;i--)if (dep[f[a][i]]>=dep[b])a=f[a][i];
if (a==b) return a;
for (int i=17;i>=0;i--)if (f[a][i]!=f[b][i])
{
a=f[a][i];b=f[b][i];
}
return f[a][0];
}
int main()
{
n=read();m=read();dep[1]=1;
for (int i=1;i<=n;i++) up[i]=i;
for (int i=1;i<n;i++){int u=read(),v=read();ins(u,v);ins(v,u);}
dfs(1);build(1,1,n);
while (m--)
{
int opt=read(),x=read();
if (opt==1)access(x);
else if (opt==2)
{
int y=read();
printf("%d\n",query(1,1,n,l[y])+query(1,1,n,l[x])-2*query(1,1,n,l[lca(x,y)])+1);
}
else printf("%d\n",MX(1,1,n,l[x],r[x]));
}
return 0;
}