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
对于每个询问操作,输出一行答案。
思路:
树链剖分,线段树维护区间内颜色段数以及左端点和右端点的颜色,
在链上进行区间合并时注意细节。
代码:
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+10;
int n,m,tol;
int head[maxn],seg[maxn],rev[maxn],top[maxn],fa[maxn];
int Size[maxn],son[maxn],dep[maxn],a[maxn],add[maxn<<2];
struct RODE
{
int to,next;
}rode[maxn*2];
struct TREE
{
int lc,rc,sum;
}tree[maxn<<2];
void add_edge(int a,int b)
{
rode[tol].to=b;
rode[tol].next=head[a];
head[a]=tol++;
}
void dfs1(int v,int father)
{
Size[v]=1;
dep[v]=dep[father]+1;
fa[v]=father;
for(int i=head[v];i!=-1;i=rode[i].next)
{
RODE e=rode[i];
if(e.to==father)continue;
dfs1(e.to,v);
Size[v]+=Size[e.to];
if(Size[son[v]]<Size[e.to]) son[v]=e.to;
}
}
void dfs2(int v,int father)
{
if(son[v])
{
seg[son[v]]=++seg[0];
rev[seg[0]]=son[v];
top[son[v]]=top[v];
dfs2(son[v],v);
}
for(int i=head[v];i!=-1;i=rode[i].next)
{
RODE e=rode[i];
if(!top[e.to])
{
seg[e.to]=++seg[0];
rev[seg[0]]=e.to;
top[e.to]=e.to;
dfs2(e.to,v);
}
}
}
void push_down(int rt)
{
if(add[rt]!=-1)
{
tree[rt<<1].sum=1;
tree[rt<<1].lc=tree[rt<<1].rc=add[rt];
tree[rt<<1|1].sum=1;
tree[rt<<1|1].lc=tree[rt<<1|1].rc=add[rt];
add[rt<<1]=add[rt<<1|1]=add[rt];
add[rt]=-1;
}
}
TREE Union(TREE x,TREE y)
{
TREE v;
v.lc=x.lc;
v.rc=y.rc;
v.sum=x.sum+y.sum;
if(x.rc==y.lc) v.sum--;
return v;
}
void build(int l,int r,int rt)
{
if(l==r)
{
tree[rt].sum=1;
tree[rt].lc=tree[rt].rc=a[rev[l]];
return;
}
int mid=(l+r)/2;
build(l,mid,rt<<1);
build(mid+1,r,rt<<1|1);
tree[rt]=Union(tree[rt<<1],tree[rt<<1|1]);
}
void update(int L,int R,int C,int l,int r,int rt)
{
if(l>=L&&r<=R)
{
add[rt]=C;
tree[rt].sum=1;
tree[rt].lc=tree[rt].rc=C;
return;
}
push_down(rt);
int mid=(l+r)/2;
if(L<=mid) update(L,R,C,l,mid,rt<<1);
if(R>mid) update(L,R,C,mid+1,r,rt<<1|1);
tree[rt]=Union(tree[rt<<1],tree[rt<<1|1]);
}
TREE query(int L,int R,int l,int r,int rt)
{
TREE v1,v2;
v1.lc=v1.rc=-1; v1.sum=0;
if(l>=L&&r<=R) return tree[rt];
push_down(rt);
int mid=(l+r)/2;
if(L<=mid&&R>mid)
{
v1=query(L,R,l,mid,rt<<1);
v2=query(L,R,mid+1,r,rt<<1|1);
return Union(v1,v2);
}
else if(L<=mid) return query(L,R,l,mid,rt<<1);
else if(R>mid) return query(L,R,mid+1,r,rt<<1|1);
else return v1;
}
void change(int x,int y,int z)
{
int fx=top[x],fy=top[y];
while(fx!=fy)
{
if(dep[fx]<dep[fy]) swap(x,y),swap(fx,fy);
update(seg[fx],seg[x],z,1,seg[0],1);
x=fa[fx],fx=top[x];
}
if(dep[x]>dep[y]) swap(x,y);
update(seg[x],seg[y],z,1,seg[0],1);
}
int work(int x,int y)
{
if(x==y) return 1;
TREE v1,v2,v3;
v1.lc=v1.rc=v2.lc=v2.rc=-1;
v1.sum=v2.sum=0;
int fx=top[x],fy=top[y];
while(fx!=fy)
{
if(dep[fx]>dep[fy])
{
v3=query(seg[fx],seg[x],1,seg[0],1);
//swap(v3.lc,v3.rc);
v1=Union(v3,v1);
x=fa[fx];fx=top[x];
}
else
{
v3=query(seg[fy],seg[y],1,seg[0],1);
v2=Union(v3,v2);
y=fa[fy];fy=top[y];
}
}
if(dep[x]<dep[y])
{
v3=query(seg[x],seg[y],1,seg[0],1);
v2=Union(v3,v2);
}
if(dep[x]>=dep[y])
{
v3=query(seg[y],seg[x],1,seg[0],1);
//swap(v3.lc,v3.rc);
v1=Union(v3,v1);
}
swap(v1.lc,v1.rc);
return Union(v1,v2).sum;
}
int main()
{
memset(add,-1,sizeof(add));
memset(head,-1,sizeof(head));
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
for(int i=1;i<n;i++)
{
int x,y;scanf("%d%d",&x,&y);
add_edge(x,y);add_edge(y,x);
}
dfs1(1,0);
seg[0]=seg[1]=rev[1]=top[1]=1;
dfs2(1,0);
build(1,seg[0],1);
while(m--)
{
char t[2];int x,y,z;scanf("%s",&t);
if(t[0]=='C')
{
scanf("%d%d%d",&x,&y,&z);
change(x,y,z);
}
else
{
scanf("%d%d",&x,&y);
printf("%d\n",work(x,y));
}
}
return 0;
}