码迷,mamicode.com
首页 > 其他好文 > 详细

BZOJ2243: [SDOI2011]染色

时间:2018-05-13 12:07:03      阅读:143      评论:0      收藏:0      [点我收藏+]

标签:上传   add   define   led   push   c++   一个   printf   void   

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]之间。

题解Here!

树上操作,首选 树链剖分/LCT。

这题就只有10w,所以树剖即可。

线段树维护:区间颜色数,区间左右颜色。

上传时:直接加,如果 左区间的右颜色==右区间的左颜色,颜色数-1。

标记下传:直接左右颜色修改,颜色数赋为1。

记得在跳树链时判断一下起始节点的颜色是否要合并。

附代码:

#include<iostream>
#include<algorithm>
#include<cstdio>
#define LSON rt<<1
#define RSON rt<<1|1
#define DATA(x) b[x].data
#define DATAL(x) b[x].left
#define DATAR(x) b[x].right
#define SIGN(x) b[x].c
#define LSIDE(x) b[x].l
#define RSIDE(x) b[x].r
#define MAXN 100010
using namespace std;
int n,m,c=1,d=1;
int val[MAXN],head[MAXN],id[MAXN],top[MAXN],deep[MAXN],son[MAXN],fa[MAXN],size[MAXN];
struct node1{
	int next,to;
}a[MAXN<<1];
struct node2{
	int data,left,right,c;
	int l,r;
}b[MAXN<<2];
inline int read(){
	int date=0,w=1;char c=0;
	while(c<‘0‘||c>‘9‘){if(c==‘-‘)w=-1;c=getchar();}
	while(c>=‘0‘&&c<=‘9‘){date=date*10+c-‘0‘;c=getchar();}
	return date*w;
}
void add(int u,int v){
	a[c].to=v;
	a[c].next=head[u];
	head[u]=c++;
	a[c].to=u;
	a[c].next=head[v];
	head[v]=c++;
}
void dfs1(int rt){
	son[rt]=0;size[rt]=1;
	for(int i=head[rt];i;i=a[i].next){
		int will=a[i].to;
		if(!deep[will]){
			deep[will]=deep[rt]+1;
			fa[will]=rt;
			dfs1(will);
			size[rt]+=size[will];
			if(size[will]>size[son[rt]])son[rt]=will;
		}
	}
}
void dfs2(int rt,int f){
	id[rt]=d++;top[rt]=f;
	if(son[rt])dfs2(son[rt],f);
	for(int i=head[rt];i;i=a[i].next){
		int will=a[i].to;
		if(will!=son[rt]&&will!=fa[rt])
		dfs2(will,will);
	}
}
void pushup(int rt){
	DATAL(rt)=DATAL(LSON);DATAR(rt)=DATAR(RSON);
	DATA(rt)=DATA(LSON)+DATA(RSON);
	if(DATAR(LSON)==DATAL(RSON))DATA(rt)--;
}
void pushdown(int rt){
	if(!SIGN(rt)||LSIDE(rt)==RSIDE(rt))return;
	SIGN(LSON)=DATAL(LSON)=DATAR(LSON)=SIGN(rt);
	DATA(LSON)=1;
	SIGN(RSON)=DATAL(RSON)=DATAR(RSON)=SIGN(rt);
	DATA(RSON)=1;
	SIGN(rt)=0;
}
void buildtree(int l,int r,int rt){
	int mid;
	LSIDE(rt)=l;
	RSIDE(rt)=r;
	if(l==r){
		DATA(rt)=0;
		return;
	}
	mid=l+r>>1;
	buildtree(l,mid,LSON);
	buildtree(mid+1,r,RSON);
	pushup(rt);
}
void update(int l,int r,int c,int rt){
	int mid;
	if(l<=LSIDE(rt)&&RSIDE(rt)<=r){
		SIGN(rt)=DATAL(rt)=DATAR(rt)=c;
		DATA(rt)=1;
		return;
	}
	pushdown(rt);
	mid=LSIDE(rt)+RSIDE(rt)>>1;
	if(l<=mid)update(l,r,c,LSON);
	if(mid<r)update(l,r,c,RSON);
	pushup(rt);
}
int query(int l,int r,int rt){
	int mid,ans=0;
	if(l<=LSIDE(rt)&&RSIDE(rt)<=r)
	return DATA(rt);
	pushdown(rt);
	mid=LSIDE(rt)+RSIDE(rt)>>1;
	if(l<=mid)ans+=query(l,r,LSON);
	if(mid<r)ans+=query(l,r,RSON);
	if(l<=mid&&mid<r&&DATAR(LSON)==DATAL(RSON))ans--;
	return ans;
}
int qcolour(int l,int r,int rt){
	int mid;
	if(l<=LSIDE(rt)&&RSIDE(rt)<=r)
	return DATAL(rt);
	pushdown(rt);
	mid=LSIDE(rt)+RSIDE(rt)>>1;
	if(l<=mid)return qcolour(l,r,LSON);
	else return qcolour(l,r,RSON);
}
void work1(int x,int y,int z){
	while(top[x]!=top[y]){
		if(deep[top[x]]<deep[top[y]])swap(x,y);
		update(id[top[x]],id[x],z,1);
		x=fa[top[x]];
	}
	if(deep[x]>deep[y])swap(x,y);
	update(id[x],id[y],z,1);
	return;
}
void work2(int x,int y){
	int s=0,left,right;
	while(top[x]!=top[y]){
		if(deep[top[x]]<deep[top[y]])swap(x,y);
		s+=query(id[top[x]],id[x],1);
		left=qcolour(id[top[x]],id[top[x]],1);
		right=qcolour(id[fa[top[x]]],id[fa[top[x]]],1);
		x=fa[top[x]];
		if(left==right)s--;
	}
	if(deep[x]>deep[y])swap(x,y);
	s+=query(id[x],id[y],1);
	printf("%d\n",s==0?1:s);
	return;
}
void work(){
	char ch[2];
	int x,y,z;
	while(m--){
		scanf("%s",ch);x=read();y=read();
		if(ch[0]==‘C‘){
			z=read();
			work1(x,y,z);
		}
		if(ch[0]==‘Q‘)work2(x,y);
	}
}
void init(){
	int u,v;
	n=read();m=read();
	for(int i=1;i<=n;i++)val[i]=read();
	for(int i=1;i<n;i++){
		u=read();v=read();
		add(u,v);
	}
	deep[1]=fa[1]=1;
	dfs1(1);
	dfs2(1,1);
	buildtree(1,n,1);
	for(int i=1;i<=n;i++)update(id[i],id[i],val[i],1);
}
int main(){
	init();
	work();
	return 0;
}

 

BZOJ2243: [SDOI2011]染色

标签:上传   add   define   led   push   c++   一个   printf   void   

原文地址:https://www.cnblogs.com/Yangrui-Blog/p/9031245.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!