天天看點

[SDOI2011] 染色

這道題,顯然我們需要樹剖一下

然後我們考慮怎麼用線段樹去維護區間顔色段數

我們會想到我們需要維護這麼幾個東西

1.區間段數

2.區間左端點的顔色

3.區間右端點的顔色

合并的時候就是左兒子的段數加上右兒子的段數,如果左兒子的右端點和右兒子的左端點是一個顔色,那麼就段數-1

因為是區間修改,是以加上一個懶标記就可以了

更新跟普通樹剖一樣,但是查詢不太一樣

這裡提供一種适用範圍更廣的做法

我是受到了這道題的啟發,那道題是求樹上最大子段和,需要維護的東西比較多,是以單純用變量不太好做。

是以我讓我們的 q u e r y query query函數傳回的是一個結構體來儲存這一段的答案的段數,左端點,右端點分别是什麼,然後我們再寫一個 m e r g e merge merge函數來合并兩個結構體,其實寫起來和 p u s h u p pushup pushup差不多,大概是這個樣子的

segment_tree merge(segment_tree l,segment_tree r){
	if(!l.sum)return r;
	if(!r.sum)return l;
	segment_tree res;
	res.lcol=l.lcol,res.rcol=r.rcol;
	res.sum=l.sum+r.sum;
	if(l.rcol==r.lcol)res.sum--;
	return res;	
}
           

那麼我們樹剖查詢的時候,開兩個 s e g m e n t _ t r e e segment\_tree segment_tree類型的結構體變量l,r,分别表示x往上跳到他們的lca的這一段的顔色段數和y跳到 l c a lca lca這一段的顔色段數

然後依次合并就可以了

但是注意一點, m e r g e merge merge函數是不滿足交換律的,是以我們要把 t o p [ x ] − x top[x]-x top[x]−x這一段放在左邊。

最後合并的時候要把l的左端點顔色和右端點顔色交換一下,因為我們要把一個區間整體反轉才能接到一起(可以畫個圖了解一下)

然後如果你隻過了hack資料的話就查一下你的查詢那一段有沒有查反就好了

c o d e   t i m e code \ time code time:

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

# define Rep(i,a,b) for(int i=a;i<=b;i++)
# define _Rep(i,a,b) for(int i=a;i>=b;i--)
# define RepG(i,u) for(int i=head[u];~i;i=e[i].next)
const int N=1e5+5;
template <typename T> void read(T &x){
	x=0;int f=1;
	char c=getchar();
	for(;!isdigit(c);c=getchar())if(c=='-')f=-1;
	for(;isdigit(c);c=getchar())x=(x<<1)+(x<<3)+c-'0';
	x*=f;
}

int n,m;
int head[N],cnt;
int a[N],_a[N];
int faz[N],son[N],dep[N],siz[N],top[N],dfn[N],tot;

struct Edge{
	int to,next;	
}e[N<<1];

void add(int x,int y){
	e[++cnt]=(Edge){y,head[x]},head[x]=cnt;	
}

struct segment_tree{
	int l,r;
	int lcol,rcol,sum;	
	int tag;
	segment_tree(){l=r=lcol=rcol=sum=tag=0;}
}seg[N<<2];

# define lc (u<<1)
# define rc (u<<1|1)

void pushup(int u){
	seg[u].sum=seg[lc].sum+seg[rc].sum;
	if(seg[lc].rcol==seg[rc].lcol)seg[u].sum--;
	seg[u].lcol=seg[lc].lcol;
	seg[u].rcol=seg[rc].rcol;	
}

void pushdown(int u){
	seg[lc].sum=1;
	seg[lc].lcol=seg[lc].rcol=seg[u].tag;
	seg[lc].tag=seg[u].tag;
	seg[rc].sum=1;
	seg[rc].lcol=seg[rc].rcol=seg[u].tag;
	seg[rc].tag=seg[u].tag;
	seg[u].tag=0;	
}

segment_tree merge(segment_tree l,segment_tree r){
	if(!l.sum)return r;
	if(!r.sum)return l;
	segment_tree res;
	res.lcol=l.lcol,res.rcol=r.rcol;
	res.sum=l.sum+r.sum;
	if(l.rcol==r.lcol)res.sum--;
	return res;	
}

void build(int u,int l,int r){
	seg[u].l=l,seg[u].r=r;
	if(l==r){seg[u].sum=1,seg[u].lcol=seg[u].rcol=_a[l];return;}
	int mid=l+r>>1;
	build(lc,l,mid);
	build(rc,mid+1,r);
	pushup(u);
}

void update(int u,int l,int r,int k){
	if(seg[u].l>=l&&seg[u].r<=r){
		seg[u].sum=1;
		seg[u].lcol=seg[u].rcol=k;
		seg[u].tag=k;
		return;
	}	
	if(seg[u].tag)pushdown(u);
	int mid=seg[u].l+seg[u].r>>1;
	if(l<=mid)update(lc,l,r,k);
	if(r>mid)update(rc,l,r,k);
	pushup(u);
}

segment_tree query(int u,int l,int r){
	if(seg[u].l>=l&&seg[u].r<=r)return seg[u];
	if(seg[u].tag)pushdown(u);
	int mid=seg[u].l+seg[u].r>>1;
	if(r<=mid)return query(lc,l,r);
	if(l>mid)return query(rc,l,r);
	return merge(query(lc,l,r),query(rc,l,r));	
}

void RouteModify(int x,int y,int k){
	while(top[x]!=top[y]){
		if(dep[top[x]]<dep[top[y]])swap(x,y);
		update(1,dfn[top[x]],dfn[x],k);
		x=faz[top[x]];	
	}
	if(dep[x]>dep[y])swap(x,y);
	update(1,dfn[x],dfn[y],k);
}

int RouteQuery(int x,int y){
	segment_tree l,r;
	while(top[x]!=top[y]){
		if(dep[top[x]]<dep[top[y]]){
			r=merge(query(1,dfn[top[y]],dfn[y]),r);
			y=faz[top[y]];	
		}
		else{
			l=merge(query(1,dfn[top[x]],dfn[x]),l);
			x=faz[top[x]];	
		}
	}
	if(dep[x]<dep[y])r=merge(query(1,dfn[x],dfn[y]),r);
	else l=merge(query(1,dfn[y],dfn[x]),l);
	swap(l.lcol,l.rcol);
	return merge(l,r).sum; 
}

void dfs1(int u,int fa){
	faz[u]=fa;
	siz[u]=1;
	dep[u]=dep[fa]+1;
	RepG(i,u){
		int v=e[i].to;
		if(v==fa)continue;
		dfs1(v,u);
		siz[u]+=siz[v];
		if(siz[v]>siz[son[u]])son[u]=v;
	}
}

void dfs2(int u,int _top){
	top[u]=_top;
	dfn[u]=++tot;
	_a[tot]=a[u];
	if(!son[u])return;
	dfs2(son[u],_top);
	RepG(i,u){
		int v=e[i].to;
		if(v==faz[u]||v==son[u])continue;
		dfs2(v,v);
	}
}

int main()
{
	memset(head,-1,sizeof(head));
	read(n),read(m);
	Rep(i,1,n)read(a[i]);
	Rep(i,1,n-1){
		int x,y;
		read(x),read(y);
		add(x,y),add(y,x);
	}
	dfs1(1,0),dfs2(1,1);
	build(1,1,n);
	Rep(i,1,m){
		char opt[10];
		int x,y,z;
		scanf("%s",opt);
		if(opt[0]=='C'){
			read(x),read(y),read(z);
			RouteModify(x,y,z);
		}
		else{
			read(x),read(y);
			printf("%d\n",RouteQuery(x,y));	
		}
	}
	return 0;
}