BZOJ 2243: [SDOI2011]染色(树链剖分)
2243: [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 1###
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 1###
3
1
2HINT###
数N<=105,操作数M<=105,所有的颜色C为整数且在[0, 10^9]之间。
题目地址: BZOJ 2243: [SDOI2011]染色
题解:
此题的关键是线段树记录的信息是什么
线段树上记三个量:
该段颜色段数,左端点颜色,右端点颜色
在合并的时候段点颜色要特别小心仔细
写法技巧和细节也很重要
其余树链剖分
www.cnblogs.com/AGFghy/
AC代码
#include<cstdio>
#include<algorithm>
using namespace std;
const int N=1e5+5;
int n,m,u,v,x,y,c,num,cnt;
int point[N<<1],next[N<<1],head[N];
int fa[N],dep[N],size[N],son[N],id[N],top[N];
int a[N],fc[N];
char pd[5];
struct node
{
int lc,rc,v,lazy;
}tree[N<<2];
void add(int u,int v)
{
point[++num]=v;
next[num]=head[u];
head[u]=num;
}
void dfs1(int now,int pre)
{
fa[now]=pre;
dep[now]=dep[pre]+1;
size[now]=1;
for (int i=head[now]; i; i=next[i])
{
int v=point[i];
if (v==pre) continue;
dfs1(v,now);
size[now]+=size[v];
if (size[v]>size[son[now]]) son[now]=v;
}
}
void dfs2(int now,int topf)
{
top[now]=topf;
id[now]=++cnt;
a[cnt]=fc[now]+1;
if (!son[now]) return;
dfs2(son[now],topf);
for (int i=head[now]; i; i=next[i])
{
int v=point[i];
if (v==fa[now] || v==son[now]) continue;
dfs2(v,v);
}
}
void pushup(int p)
{
tree[p].lc=tree[p<<1].lc;
tree[p].rc=tree[(p<<1)+1].rc;
tree[p].v=tree[p<<1].v+tree[(p<<1)+1].v-(tree[p<<1].rc==tree[(p<<1)+1].lc);
}
void pushdown(int p)
{
if (tree[p].lazy)
{
tree[p<<1].lc=tree[p<<1].rc=tree[p<<1].lazy=tree[p].lazy; tree[p<<1].v=1;
tree[(p<<1)+1].lc=tree[(p<<1)+1].rc=tree[(p<<1)+1].lazy=tree[p].lazy; tree[(p<<1)+1].v=1;
tree[p].lazy=0;
}
}
void build(int l,int r,int p)
{
if (l==r)
{
tree[p].lc=tree[p].rc=a[l];
tree[p].v=1;
return;
}
int mid=(l+r)>>1;
build(l,mid,p<<1);
build(mid+1,r,(p<<1)+1);
pushup(p);
}
void update(int l,int r,int p,int s,int t,int c)
{
if (l==s && r==t)
{
tree[p].lc=tree[p].rc=tree[p].lazy=c;
tree[p].v=1;
return;
}
pushdown(p);
int mid=(l+r)>>1;
if (t<=mid) update(l,mid,p<<1,s,t,c);
else if (s>mid) update(mid+1,r,(p<<1)+1,s,t,c);
else
{
update(l,mid,p<<1,s,mid,c);
update(mid+1,r,(p<<1)+1,mid+1,t,c);
}
pushup(p);
}
node query(int l,int r,int p,int s,int t)
{
if (l==s && r==t) return tree[p];
pushdown(p);
int mid=(l+r)>>1;
if (t<=mid) return query(l,mid,p<<1,s,t);
else if (s>mid) return query(mid+1,r,(p<<1)+1,s,t);
else
{
node res,s1,s2;
s1=query(l,mid,p<<1,s,mid); s2=query(mid+1,r,(p<<1)+1,mid+1,t);
res.lc=s1.lc; res.rc=s2.rc;
res.v=s1.v+s2.v-(s1.rc==s2.lc);
return res;
}
}
void cover(int x,int y,int c)
{
while (top[x]!=top[y])
{
if (dep[top[x]]<dep[top[y]]) swap(x,y);
update(1,n,1,id[top[x]],id[x],c);
x=fa[top[x]];
}
if (dep[x]>dep[y]) swap(x,y);
update(1,n,1,id[x],id[y],c);
}
int seg(int x,int y)
{
int xc=-1,yc=-1,ans=0;
node now;
while (top[x]!=top[y])
{
if (dep[top[x]]<dep[top[y]]) swap(x,y),swap(xc,yc);
now=query(1,n,1,id[top[x]],id[x]);
ans+=now.v-(now.rc==xc);
xc=now.lc; x=fa[top[x]];
}
if (dep[x]>dep[y]) swap(x,y),swap(xc,yc);
now=query(1,n,1,id[x],id[y]);
ans+=now.v-(now.lc==xc)-(now.rc==yc);
return ans;
}
int main()
{
scanf("%d%d",&n,&m);
for (int i=1; i<=n; i++)
scanf("%d",&fc[i]);
for (int i=1; i<n; i++)
{
scanf("%d%d",&u,&v);
add(u,v); add(v,u);
}
dfs1(1,0);
dfs2(1,1);
build(1,n,1);
while (m--)
{
scanf("%s",pd);
if (pd[0]=='C')
{
scanf("%d%d%d",&x,&y,&c);
c++;
cover(x,y,c);
}
if (pd[0]=='Q')
{
scanf("%d%d",&x,&y);
printf("%d\n",seg(x,y));
}
}
}