HYSBZ - 2243 染色

给定一棵有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<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define lson root<<1
#define rson  (root<<1)|1
using namespace std;
const int maxn=1e5+5;
struct node{
	int to,nxt;
}ed[maxn<<1];
int head[maxn],cnt;
int dep[maxn],sz[maxn],son[maxn],p[maxn],top[maxn],fa[maxn];
int initcol[maxn],ndcol[maxn],pos;
void addedge(int u,int v){
	ed[cnt].to=v;
	ed[cnt].nxt=head[u];
	head[u]=cnt++;
}
void dfs1(int u,int pre,int d){
	dep[u]=d;
	sz[u]=1;
	fa[u]=pre;
	for(int i=head[u];~i;i=ed[i].nxt){
		int v=ed[i].to;
		if(v!=pre){
			dfs1(v,u,d+1);
			sz[u]+=sz[v];
			if(son[u]==-1||sz[son[u]]<sz[v])son[u]=v;
		}
	}
}
void dfs2(int u,int tp){
	top[u]=tp;
	p[u]=pos++;
	initcol[p[u]]=ndcol[u];
	if(son[u]==-1){
		return ;
	}
	dfs2(son[u],tp);
	for(int i=head[u];~i;i=ed[i].nxt){
		int v=ed[i].to;
		if(v==fa[u]||v==son[u])continue;
		dfs2(v,v);
	}
}
struct T{
	int l,r,lc,rc,mark,num;
}tree[maxn<<2];
void pushup(int root){
	tree[root].lc=tree[lson].lc;
	tree[root].rc=tree[rson].rc;
	tree[root].num=tree[lson].num+tree[rson].num-(tree[lson].rc==tree[rson].lc);
	return ;
}
void pushdown(int root){
	if(tree[root].l==tree[root].r)return ;
	if(tree[root].mark==0)return ;
	tree[lson].mark=tree[rson].mark=tree[root].mark;
	tree[lson].lc=tree[lson].rc=tree[rson].lc=tree[rson].rc=tree[root].mark;
	tree[lson].num=tree[rson].num=1;
	tree[root].mark=0;
	return ;
}
void build(int l,int r,int root){		
	tree[root].l=l,tree[root].r=r;
	tree[root].lc=initcol[l];
	tree[root].rc=initcol[r];
	tree[root].mark=0;
	if(l==r){
		tree[root].num=1;
		return ;
	}
	int mid=l+r>>1;
	build(l,mid,lson);
	build(mid+1,r,rson);
	pushup(root);
	return ;
}
void update(int l,int r,int col,int root){
	if(tree[root].l==l&&tree[root].r==r){
		tree[root].lc=tree[root].rc=col;
		tree[root].num=1;
		tree[root].mark=col;
		return ;
	}
	pushdown(root);
	int mid=tree[root].l+tree[root].r>>1;
	if(r<=mid)update(l,r,col,lson);
	else if(l>mid)update(l,r,col,rson);
	else {
		update(l,mid,col,lson);
		update(mid+1,r,col,rson);
	}
	pushup(root);
	return ;
}
int ask(int a,int root){
	if(a==tree[root].r)return tree[root].rc;
	if(a==tree[root].l)return tree[root].lc;
	pushdown(root);
	int mid=tree[root].l+tree[root].r>>1;
	if(a<=mid)return ask(a,lson);
	else if(a>mid)return ask(a,rson);
}
int query(int l,int r,int root){
	if(tree[root].l==l&&tree[root].r==r){
		return tree[root].num;
	}
	pushdown(root);
	int mid=(tree[root].l+tree[root].r)>>1;
	if(r<=mid)return query(l,r,lson);
	else if(l>mid)return query(l,r,rson);
	else {
		return query(l,mid,lson)+query(mid+1,r,rson)-(tree[lson].rc==tree[rson].lc);
	}	
}
void up(int u,int v,int col){
	int f1=top[u],f2=top[v];
	while(f1!=f2){
		if(dep[f1]<dep[f2]){
			swap(f1,f2);
			swap(u,v);
		}
		update(p[f1],p[u],col,1);
		u=fa[f1];
		f1=top[u];
	}
	if(dep[u]<dep[v])swap(u,v);
	update(p[v],p[u],col,1);
}
int getnum(int u,int v){
	int f1=top[u],f2=top[v];
	int re=0;
	while(f1!=f2){
		if(dep[f1]<dep[f2]){
			swap(f1,f2);
			swap(u,v);
		}
		re+=query(p[f1],p[u],1)-(ask(p[fa[f1]],1)==ask(p[f1],1));
		u=fa[f1];
		f1=top[u];
	}
	if(dep[u]<dep[v])swap(u,v);
	re+=query(p[v],p[u],1);
	return re;
}
int main()
{
	memset(son,-1,sizeof(son));
	memset(head,-1,sizeof(head));
	int n,m;
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++){
		scanf("%d",&ndcol[i]);
	}
	for(int i=1;i<n;i++){
		int u,v;
		scanf("%d%d",&u,&v);
		addedge(u,v);
		addedge(v,u);
	}
	dfs1(1,0,0);
	dfs2(1,1);
	build(0,n,1);
	while(m--){
		char str[2];
		int a,b,c;
		scanf("%s%d%d",str,&a,&b);
		if(str[0]=='C'){
			scanf("%d",&c);	
			up(a,b,c);	
		}
		else {
			printf("%d\n",getnum(a,b));
		}
		getchar();
	}
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值