bzoj2243: [SDOI2011]染色(树链剖分)
www.cnblogs.com/shaokele/
bzoj2243: [SDOI2011]染色##
Time Limit: 20 Sec
Memory Limit: 512 MBDescription###
给定一棵有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;
}