题目:luogu2486.
题目大意:在一棵树上,支持以下操作:
1.格式C u v x,表示将点u到点v的路径上的点都染成颜色x.
2.格式 Q u v,表示查询点u到点v的路径上相同颜色块的数量.
这道题就是树剖板子题,难点在于如何维护线段树.
线段树其实也不是很难,只需要每个节点维护左端点颜色,右端点颜色,以及颜色块数量就可以了.
但是有一个小问题,树剖的询问,也就是寻找每一条重链的答案该如何合并.
我们直接多定义两个树uc,vc表示u,v当前链的顶端的颜色,交换的时候顺便把这uc,vc交换就可以了.
然后就是很裸的树剖了.
等等树剖的板子怎么敲...
注意一个坑点:初始颜色可以为0.
代码如下:
#include<bits/stdc++.h>
using namespace std;
#define Abigail inline void
typedef long long LL;
const int N=100000;
struct side{
int y,next;
}e[N*2+5];
struct node{
int dad,son,deep,v,dfn,top,size;
}nod[N+5];
struct tree{
int l,r,lc,rc,sum,tag;
}tr[N*5];
int order[N+5],lin[N+5],n,m,t,top;
void ins(int X,int Y){
e[++top].y=Y;
e[top].next=lin[X];
lin[X]=top;
}
int dfs1(int k,int father){
nod[k].dad=father;
nod[k].deep=nod[father].deep+1;
nod[k].size=1;
for (int i=lin[k];i;i=e[i].next)
if (e[i].y^father){
dfs1(e[i].y,k);
nod[k].size+=nod[e[i].y].size;
if (nod[nod[k].son].size<nod[e[i].y].size) nod[k].son=e[i].y;
}
}
void dfs2(int k,int start){
nod[k].dfn=++t;
order[t]=k;
nod[k].top=start;
if (nod[k].son) dfs2(nod[k].son,start);
for (int i=lin[k];i;i=e[i].next)
if (e[i].y^nod[k].dad&&e[i].y^nod[k].son) dfs2(e[i].y,e[i].y);
}
void pushup(int k){
int ls=k<<1,rs=k<<1|1;
tr[k].lc=tr[ls].lc;tr[k].rc=tr[rs].rc;
tr[k].sum=tr[ls].sum+tr[rs].sum;
if (tr[ls].rc==tr[rs].lc) tr[k].sum--;
}
void pushdown(int k){
if (tr[k].tag^-1){
int ls=k<<1,rs=k<<1|1;
tr[ls].lc=tr[ls].rc=tr[rs].lc=tr[rs].rc=tr[k].tag;
tr[ls].sum=tr[rs].sum=1;
tr[ls].tag=tr[rs].tag=tr[k].tag;
tr[k].tag=-1;
}
}
void build(int L,int R,int k=1){
tr[k].l=L;tr[k].r=R;tr[k].tag=-1;
if (L==R){
tr[k].lc=tr[k].rc=nod[order[L]].v;
tr[k].sum=1;
return;
}
int mid=L+R>>1;
build(L,mid,k<<1);build(mid+1,R,k<<1|1);
pushup(k);
}
void change(int L,int R,int v,int k=1){
if (tr[k].l==L&&tr[k].r==R){
tr[k].tag=v;
tr[k].lc=tr[k].rc=v;
tr[k].sum=1;
return;
}
pushdown(k);
int mid=tr[k].l+tr[k].r>>1;
if (R<=mid) change(L,R,v,k<<1);
else if (L>mid) change(L,R,v,k<<1|1);
else change(L,mid,v,k<<1),change(mid+1,R,v,k<<1|1);
pushup(k);
}
struct tree1{
int lc,rc,sum;
};
tree1 query(int L,int R,int k=1){
if (tr[k].l==L&&tr[k].r==R) return (tree1){tr[k].lc,tr[k].rc,tr[k].sum};
int mid=tr[k].l+tr[k].r>>1;
pushdown(k);
if (R<=mid) return query(L,R,k<<1);
else if (L>mid) return query(L,R,k<<1|1);
else {
tree1 u=query(L,mid,k<<1),v=query(mid+1,R,k<<1|1),o;
o.lc=u.lc;o.rc=v.rc;
o.sum=u.sum+v.sum;
if (u.rc==v.lc) o.sum--;
return o;
}
}
void Change(int u,int v,int c){
while (nod[u].top^nod[v].top){
if (nod[nod[u].top].deep<nod[nod[v].top].deep) swap(u,v);
change(nod[nod[u].top].dfn,nod[u].dfn,c);
u=nod[nod[u].top].dad;
}
if (nod[u].deep>nod[v].deep) swap(u,v);
change(nod[u].dfn,nod[v].dfn,c);
}
int Query(int u,int v){
tree1 o;
int uc=-1,vc=-1,sum=0;
while (nod[u].top^nod[v].top){
if (nod[nod[u].top].deep<nod[nod[v].top].deep) swap(u,v),swap(uc,vc);
o=query(nod[nod[u].top].dfn,nod[u].dfn);
sum+=o.sum;
if (uc==o.rc) sum--;
uc=o.lc;
u=nod[nod[u].top].dad;
}
if (nod[u].deep>nod[v].deep) swap(u,v),swap(uc,vc);
o=query(nod[u].dfn,nod[v].dfn);
sum+=o.sum;
if (o.lc==uc) sum--;
if (o.rc==vc) sum--;
return sum;
}
char rc(){
char c=getchar();
for (;c<'A'||c>'Z';c=getchar());
return c;
}
int ri(){
int x=0,y=1;
char c=getchar();
for (;c<'0'||c>'9';c=getchar()) if (c=='-') y=-1;
for (;c<='9'&&c>='0';c=getchar()) x=x*10+c-'0';
return x*y;
}
Abigail into(){
n=ri();m=ri();
for (int i=1;i<=n;i++)
nod[i].v=ri();
int x,y;
for (int i=1;i<n;i++){
x=ri();y=ri();
ins(x,y);ins(y,x);
}
}
Abigail work(){
dfs1(1,0);
dfs2(1,1);
build(1,n);
char opt;
int u,v,c;
for (int i=1;i<=m;i++){
opt=rc();
if (opt=='C'){
u=ri();v=ri();c=ri();
Change(u,v,c);
}else{
u=ri();v=ri();
printf("%d\n",Query(u,v));
}
}
}
Abigail outo(){
}
int main(){
into();
work();
outo();
return 0;
}