[bzoj4817] [SDOI2017]树点涂色

Description

Bob有一棵n个点的有根树,其中1号点是根节点。Bob在每个点上涂了颜色,并且每个点上的颜色不同。定义一条路

径的权值是:这条路径上的点(包括起点和终点)共有多少种不同的颜色。Bob可能会进行这几种操作:

1 x:

把点x到根节点的路径上所有的点染上一种没有用过的新颜色。

2 x y:

求x到y的路径的权值。

3 x

在以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

solution

\(LCT\)好题。

对于\(1\)操作,注意到每次都是从\(x\)到根的修改,而且每次颜色都不一样,可以类比于\(LCT\)\(access\)

所以开一颗\(LCT\)\(LCT\)内每一颗\(splay\)维护一种颜色,然后改颜色直接\(access\)就好了。

考虑怎么维护问的东西。

注意到要同时维护链上信息和子树信息,可以考虑拿一个\(dfs\)序建的线段树来维护每个点到根节点路径的权值。

然后每次\(access\)的时候,实边变虚边就把子树内所有权值\(+1\),反之\(-1\)

然后对于\(3\)操作拿线段树记一下\(max\)就好了。

#include<bits/stdc++.h>
using namespace std;

void read(int &x) {
    x=0;int f=1;char ch=getchar();
    for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-f;
    for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0';x*=f;
}

void print(int x) {
    if(x<0) putchar('-'),x=-x;
    if(!x) return ;print(x/10),putchar(x%10+48);
}
void write(int x) {if(!x) putchar('0');else print(x);putchar('\n');}

const int maxn = 1e5+1;

int fa[maxn],son[maxn][2],dfn[maxn],sz[maxn],head[maxn],tot,dfn_cnt,R[maxn],dep[maxn],n,m,f[maxn][20];
struct edge {int to,nxt;}e[maxn<<1];

void add(int u,int v) {e[++tot]=(edge){v,head[u]},head[u]=tot;}
void ins(int u,int v) {add(u,v),add(v,u);}

#define ls p<<1
#define rs p<<1|1
#define mid ((l+r)>>1)

struct Segment_Tree {
	int tr[maxn],tag[maxn];
	void update(int p) {tr[p]=max(tr[ls],tr[rs]);}
	void push_tag(int p,int v) {tr[p]+=v,tag[p]+=v;}
	void pushdown(int p) {
		if(!tag[p]) return ;
		tr[ls]+=tag[p],tr[rs]+=tag[p],tag[ls]+=tag[p],tag[rs]+=tag[p];
		tag[p]=0;
	}
	void modify(int p,int l,int r,int x,int y,int v) {
		if(x<=l&&r<=y) return tr[p]+=v,tag[p]+=v,void();
		pushdown(p);
		if(x<=mid) modify(ls,l,mid,x,y,v);
		if(y>mid) modify(rs,mid+1,r,x,y,v);
		update(p);
	}
	int query(int p,int l,int r,int x,int y) {
		if(x<=l&&r<=y) return tr[p];
		int ans=0;pushdown(p);
		if(x<=mid) ans=max(ans,query(ls,l,mid,x,y));
		if(y>mid) ans=max(ans,query(rs,mid+1,r,x,y));
		return ans;
	}
	void build(int p,int l,int r) {
		if(l==r) return tr[p]=dep[R[l]],void();
		build(ls,l,mid),build(rs,mid+1,r);
		update(p);
	}
}SGT;

#undef ls
#undef rs
#undef mid 

struct Input_Tree {
	void dfs(int x,int F) {
		fa[x]=F,sz[x]=1,dfn[x]=++dfn_cnt,R[dfn_cnt]=x,f[x][0]=F,dep[x]=dep[F]+1;
		for(int i=1;i<=19;i++) f[x][i]=f[f[x][i-1]][i-1];
		for(int i=head[x];i;i=e[i].nxt)
			if(e[i].to!=F) dfs(e[i].to,x),sz[x]+=sz[e[i].to];
	}
	int lca(int x,int y) {
		if(dep[x]<dep[y]) swap(x,y);
		for(int i=19;~i;i--) if(dep[f[x][i]]>=dep[y]) x=f[x][i];
		if(x==y) return x;
		for(int i=19;~i;i--) if(f[x][i]!=f[y][i]) x=f[x][i],y=f[y][i];
		return f[x][0];
	}
}T;

struct Link_Cut_Tree {
	int is_root(int x) {return son[fa[x]][0]!=x&&son[fa[x]][1]!=x;}
	int which(int x) {return son[fa[x]][1]==x;}
	void rotate(int x) {
		int F=fa[x],ff=fa[F],w=which(x);
		if(!is_root(F)) son[ff][son[ff][1]==F]=x;
		fa[x]=ff,fa[F]=x,fa[son[x][w^1]]=F,son[F][w]=son[x][w^1],son[x][w^1]=F;
	}
	void splay(int x) {
		while(!is_root(x)) {
			int y=fa[x],z=fa[y];
			if(!is_root(y)) rotate(((son[y][1]==x)^(son[z][1]==y))?x:y);
			rotate(x);
		}
	}
	int pre(int x) {
		while(son[x][0]) x=son[x][0];
		return x;
	}
	void access(int x) {
		for(int t=0;x;t=x,x=fa[x]) {
			splay(x);
			if(son[x][1]) {
				int p=pre(son[x][1]);
				SGT.modify(1,1,n,dfn[p],dfn[p]+sz[p]-1,1);
			}
			son[x][1]=t;
			if(t) {
				int p=pre(t);
				SGT.modify(1,1,n,dfn[p],dfn[p]+sz[p]-1,-1);
			}
		}
	}
}LCT;

int main() {
	read(n),read(m);
	for(int i=1,x,y;i<n;i++) read(x),read(y),ins(x,y);
	T.dfs(1,0);SGT.build(1,1,n);
	for(int op,x,y,i=1;i<=m;i++) {
		read(op),read(x);
		if(op==1) LCT.access(x);
		else if(op==2) {
			read(y);int ans=1,tmp=dfn[T.lca(x,y)];
			ans+=SGT.query(1,1,n,dfn[x],dfn[x])+SGT.query(1,1,n,dfn[y],dfn[y]);
			ans-=2*SGT.query(1,1,n,tmp,tmp);write(ans);
		} else write(SGT.query(1,1,n,dfn[x],dfn[x]+sz[x]-1));
	}
	return 0;
}
posted @ 2018-12-19 16:54  Hyscere  阅读(215)  评论(0编辑  收藏  举报