bzoj2243: [SDOI2011]染色

Description

给定一棵有n个节点的无根树和m个操作,操作有2类:
1、将节点a到节点b路径上所有点都染成颜色c;
2、询问节点a到节点b路径上的颜色段数量(连续相同颜色被认为是同一段),
如“112221”由3段组成:“11”、“222”和“1”。
请你写一个程序依次完成这m个操作。

Input

第一行包含2个整数n和m,分别表示节点数和操作数;
第二行包含n个正整数表示n个节点的初始颜色
下面 行每行包含两个整数x和y,表示x和y之间有一条无向边。
下面 行每行描述一个操作:
“C a b c”表示这是一个染色操作,把节点a到节点b路径上所有点(包括a和b)都染成颜色c;
“Q a b”表示这是一个询问操作,询问节点a到节点b(包括a和b)路径上的颜色段数量。

Output

对于每个询问操作,输出一行答案。

Sample Input

6 5
2 2 1 2 1 1
1 2
1 3
2 4
2 5
2 6
Q 3 5
C 2 1 1
Q 3 5
C 5 1 2
Q 3 5

Sample Output

3
1
2

HINT

数N<=10^5,操作数M<=10^5,所有的颜色C为整数且在[0, 10^9]之间。

题解:

树剖..维护区间左端点颜色,右端点颜色,然后维护区间颜色段数量,合并就判断一下左儿子的右端点右儿子的左端点颜色是否相同

#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>
#include <algorithm>
using namespace std;
const int maxn=300000+10;
struct node{
	int cnum,cl,cr;
	int lazy;
	node(){
		cnum=0;
		cl=cr=lazy=-1;
	}
}nd[maxn*8];
int top[maxn],size[maxn],son[maxn];
int fa[maxn],dep[maxn],tid[maxn];
int td=0;
vector<int>A[maxn];
int color[maxn];
int num[maxn];
int n;
inline void dfs1(int x,int d,int f){
	dep[x]=d;
	size[x]=1;
	fa[x]=f;
	for(int i=0;i<A[x].size();i++){
		int u=A[x][i];
		if(u==f)
			continue;
		dfs1(u,d+1,x);
		size[x]+=size[u];
		if(size[son[x]]<size[u])
			son[x]=u;
	}
}
inline void dfs2(int x,int tp){
	tid[x]=++td;
	top[x]=tp;
	if(!son[x])
		return ;
	dfs2(son[x],tp);
	for(int i=0;i<A[x].size();i++){
		int u=A[x][i];
		if(u==fa[x]||u==son[x])
			continue;
		dfs2(u,u);
	}
}
inline void pushdown(int o){
	if(nd[o].lazy!=-1){
		nd[o<<1].cnum=nd[o<<1|1].cnum=1;
		nd[o<<1].cl=nd[o<<1].cr=nd[o<<1|1].cl=nd[o<<1|1].cr=nd[o].lazy;
		nd[o<<1].lazy=nd[o<<1|1].lazy=nd[o].lazy;
		nd[o].lazy=-1;
	}
}
inline void pushup(int o){
	nd[o].cl=nd[o<<1].cl,nd[o].cr=nd[o<<1|1].cr;
	nd[o].cnum=nd[o<<1].cnum+nd[o<<1|1].cnum-(nd[o<<1].cr==nd[o<<1|1].cl);
}
inline void change(int o,int l,int r,int L,int R,int x){
	pushdown(o);
	if(L<=l&&r<=R){
		nd[o].lazy=x;
		nd[o].cl=nd[o].cr=x;
		nd[o].cnum=1;
		return ;
	}
	else {
		int mid=(l+r)>>1;
		if(mid>=L)
			change(o<<1,l,mid,L,R,x);
		if(mid<R)
			change(o<<1|1,mid+1,r,L,R,x);
		pushup(o);
	}
}
inline void build(int o,int l,int r){
	if(l==r){
		nd[o].cl=nd[o].cr=num[l];
		nd[o].lazy=-1,nd[o].cnum=1;
		return ;
	}
	else {
		int mid=(l+r)>>1;
		build(o<<1,l,mid);
		build(o<<1|1,mid+1,r);
		pushup(o);
	}
}
inline node query(int o,int l,int r,int L,int R){
	pushdown(o);
	if(L<=l&&r<=R)
		return nd[o];
	else {
		int mid=(l+r)>>1;
		node ll,rr,ans;
		if(mid>=L){
			ll=query(o<<1,l,mid,L,R);
			ans.cnum+=ll.cnum;
			ans.cl=ll.cl;
			ans.cr=ll.cr;
		}
		if(mid<R){
			rr=query(o<<1|1,mid+1,r,L,R);
			ans.cnum+=rr.cnum;
			if(ans.cl==-1)
				ans.cl=rr.cl;
			ans.cr=rr.cr;
		}
		if(ll.cnum&&rr.cnum){
			if(ll.cr==rr.cl)
				ans.cnum--;
		}
		return ans;
	}
}
inline int Query(int x,int y){
	int ans=0;
	int lstx=-1,lsty=-1;
	while(top[x]!=top[y]){
		if(dep[top[x]]<dep[top[y]]){
			swap(x,y);
			swap(lstx,lsty);
		}
		node ndd=query(1,1,n,tid[top[x]],tid[x]);
		ans+=ndd.cnum;
		if(lstx!=-1){
			if(ndd.cr==lstx)
				ans--;
		}
		lstx=ndd.cl;
		x=fa[top[x]];
	}
	if(dep[x]>dep[y]){
		swap(x,y);
		swap(lstx,lsty);
	}
	node ndd=query(1,1,n,tid[x],tid[y]);
	ans+=ndd.cnum;
	if(lsty!=-1){
		if(ndd.cr==lsty)
			ans--;
	}
	if(lstx!=-1){
		if(ndd.cl==lstx)
			ans--;
	}
	return ans;
}
inline void Change(int x,int y,int z){
	while(top[x]!=top[y]){
		if(dep[top[x]]<dep[top[y]])
			swap(x,y);
		change(1,1,n,tid[top[x]],tid[x],z);
		x=fa[top[x]];
	}
	if(dep[x]>dep[y])
		swap(x,y);
	change(1,1,n,tid[x],tid[y],z);
}
int main(){
	//int size = 50 << 20;
	//char *p = (char*)malloc(size) + size;
	//__asm__("movl %0, %%esp\n" :: "r"(p));
	//freopen("a.in","r",stdin);
	//freopen("a.out","w",stdout);
	int m;
	scanf("%d %d",&n,&m);
	for(int i=1;i<=n;i++)
		scanf("%d",&color[i]);
	int x,y;
	for(int i=1;i<n;i++){
		scanf("%d %d",&x,&y);
		A[x].push_back(y);
		A[y].push_back(x);
	}
	dfs1(1,1,1);
	dfs2(1,1);
	for(int i=1;i<=n;i++)
		num[tid[i]]=color[i];
	build(1,1,n);
	char c;
	int z;
	while(m--){
		cin>>c;
		if(c=='C'){
			scanf("%d %d %d",&x,&y,&z);
			Change(x,y,z);
		}
		else {
			scanf("%d %d",&x,&y);
			printf("%d\n",Query(x,y));
		}
	}
return 0;
}

ps:我比较弱,bzoj上一直re,但luogu上ac了,如果有神犇知道是怎么回事请联系蒟蒻qwq

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值