bzoj2243: [SDOI2011]染色(树链剖分)

www.cnblogs.com/shaokele/


bzoj2243: [SDOI2011]染色##

  Time Limit: 20 Sec
  Memory Limit: 512 MB

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<=105,操作数M<=105,所有的颜色C为整数且在[0, 10^9]之间。
  

题目地址:  bzoj2243: [SDOI2011]染色

题目大意: 已经很简洁了

  

题解:

  裸的树链剖分
  
  只是要记该段颜色段数,左端点颜色,右端点颜色这三个东西
  
  在合并的时候处理颜色要特别小心仔细
  
  具体看代码


AC代码

#include <cstdio> 
#include <algorithm>
using namespace std;
const int N=1e5+5;
int n,Q,cnt,num;
int fc[N],a[N];
int last[N],lazy[N<<2];
inline int read(){
	int x=0,f=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
	return x*f;
}
struct edge{
	int to,next;
}e[N<<1];
struct note{
	int lcol,rcol,val;
}T[N<<2];
void add_edge(int u,int v){
	e[++cnt]=(edge){v,last[u]};last[u]=cnt;
	e[++cnt]=(edge){u,last[v]};last[v]=cnt;
}
int fa[N],sz[N],dep[N],son[N];
void dfs1(int u,int father){
	fa[u]=father;sz[u]=1;
	dep[u]=dep[father]+1;
	for(int i=last[u];i;i=e[i].next){
		int v=e[i].to;
		if(v==father)continue;
		dfs1(v,u);
		sz[u]+=sz[v];
		if(sz[v]>sz[son[u]])son[u]=v;
	}
}
int pos[N],top[N];
void dfs2(int u,int chain){
	top[u]=chain;
	pos[u]=++num;
	a[num]=fc[u]+1;
	if(!son[u])return;
	dfs2(son[u],chain);
	for(int i=last[u];i;i=e[i].next){
		int v=e[i].to;
		if(v!=fa[u] && v!=son[u])
			dfs2(v,v);
	}
}
void pushup(int k){
	T[k].lcol=T[k<<1].lcol;
	T[k].rcol=T[k<<1|1].rcol;
	T[k].val=T[k<<1].val+T[k<<1|1].val-(T[k<<1].rcol==T[k<<1|1].lcol);
}
void pushdown(int k){
	if(lazy[k]){
		T[k<<1].lcol=T[k<<1].rcol=lazy[k<<1]=lazy[k];T[k<<1].val=1;
		T[k<<1|1].lcol=T[k<<1|1].rcol=lazy[k<<1|1]=lazy[k];T[k<<1|1].val=1;
		lazy[k]=0;
	}
}
void build(int k,int l,int r){
	if(l==r){
		T[k]=(note){a[l],a[l],1};
		return;
	}
	int mid=(l+r)>>1;
	build(k<<1,l,mid);
	build(k<<1|1,mid+1,r);
	pushup(k);
}
void update(int k,int l,int r,int L,int R,int col){
	if(l==L && R==r){
		T[k]=(note){col,col,1};
		lazy[k]=col;
		return;
	}
	pushdown(k);
	int mid=(l+r)>>1;
	if(R<=mid)update(k<<1,l,mid,L,R,col);
	else if(L>mid)update(k<<1|1,mid+1,r,L,R,col);
	else update(k<<1,l,mid,L,mid,col),update(k<<1|1,mid+1,r,mid+1,R,col);
	pushup(k);
}
void change(int a,int b,int col){
	while(top[a]!=top[b]){
		if(dep[top[a]]<dep[top[b]])swap(a,b);
		update(1,1,n,pos[top[a]],pos[a],col);
		a=fa[top[a]];
	}
	if(dep[a]>dep[b])swap(a,b);
	update(1,1,n,pos[a],pos[b],col);
}
note query(int k,int l,int r,int L,int R){
	if(l==L && R==r)return T[k];
	pushdown(k);
	int mid=(l+r)>>1;
	if(R<=mid)return query(k<<1,l,mid,L,R);
	else if(L>mid)return query(k<<1|1,mid+1,r,L,R);
	else{
		note res,Lnote,Rnote;
		Lnote=query(k<<1,l,mid,L,mid);
		Rnote=query(k<<1|1,mid+1,r,mid+1,R);
		res.lcol=Lnote.lcol;
		res.rcol=Rnote.rcol;
		res.val=Lnote.val+Rnote.val-(Lnote.rcol==Rnote.lcol);
		return res;
	}
}
int solve(int a,int b){
	int acol=-1,bcol=-1,res=0;
	note now;
	while(top[a]!=top[b]){
		if(dep[top[a]]<dep[top[b]])swap(a,b),swap(acol,bcol);
		now=query(1,1,n,pos[top[a]],pos[a]);
		res+=now.val-(now.rcol==acol);
		acol=now.lcol;a=fa[top[a]];
	}
	if(dep[a]>dep[b])swap(a,b),swap(acol,bcol);
	now=query(1,1,n,pos[a],pos[b]);
	res+=now.val-(now.lcol==acol)-(now.rcol==bcol);
	return res;
}
int main(){
	n=read();Q=read();
	for(int i=1;i<=n;i++)fc[i]=read();
	for(int i=1;i<n;i++){
		int u=read(),v=read();
		add_edge(u,v);
	}
	dfs1(1,0);
	dfs2(1,1);
	build(1,1,n);
	while(Q--){
		scanf("\n");
		int x,y,col;
		char op=getchar();
		if(op=='Q'){
			scanf("%d%d",&x,&y);
			printf("%d\n",solve(x,y));
		}else{
			scanf("%d%d%d",&x,&y,&col);
			change(x,y,col+1);
		}
	}
	return 0;
}
posted @ 2018-08-02 22:02  skl_win  阅读(119)  评论(0编辑  收藏  举报
Live2D