描述
给定一棵有n个节点的无根树和m个操作,操作有2类:
1、将节点a到节点b路径上所有点都染成颜色c;
2、询问节点a到节点b路径上的颜色段数量(连续相同颜色被认为是同一段),如“112221”由3段组成:“11”、“222”和“1”。
请你写一个程序依次完成这m个操作。
输入
第一行包含2个整数n和m,分别表示节点数和操作数;
第二行包含n个正整数表示n个节点的初始颜色
下面n-1行每行包含两个整数x和y,表示x和y之间有一条无向边。
下面m行每行描述一个操作:
“C a b c”表示这是一个染色操作,把节点a到节点b路径上所有点(包括a和b)都染成颜色c;
“Q a b”表示这是一个询问操作,询问节点a到节点b(包括a和b)路径上的颜色段数量。
输出
对于每个询问操作,输出一行答案。
样例输入 [复制]
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
样例输出 [复制]
3
1
2
数据范围:
n<=1e5,m<=1e5,int不会爆
思路:
基本上是一个裸的树链剖分 只是注意,维护查询路径的时候,
两个相邻的重链的端点值的颜色可能一样,–ans
所以要维护一个上一个的端点颜色
代码:
(全部用结构体更简洁。。。)
#include<iostream>
#include<cstdio>
#include<cstring>
#include<iomanip>
#include<vector>
#define lc (p<<1)
#define rc ((p<<1)|1)
#define pf printf
#define sf scanf
using namespace std;
const int maxn=1e5+10;
int n,m,seg[maxn],rev[maxn],top[maxn],dep[maxn],fa[maxn],son[maxn],siz[maxn],num[maxn];
int cl[maxn<<2],cr[maxn<<2],sum[maxn<<2],laz[maxn<<2];
vector <int> G[maxn];
struct pi{
int s,cl,cr;
};
inline pi mergep(pi a,pi b){
pi ans;
ans.s=a.s+b.s;ans.cl=a.cl,ans.cr=b.cr;
if(a.cr==b.cl)--ans.s;
return ans;
}
void dfs1(int u,int f){
dep[u]=dep[f]+1;fa[u]=f;siz[u]=1;
for(int i=0;i<G[u].size();++i){
int v=G[u][i];
if(v==f)continue;
dfs1(v,u);
siz[u]+=siz[v];
if(siz[v]>siz[son[u]])son[u]=v;
}
}
void dfs2(int u){
if(son[u]){
seg[son[u]]=++seg[0];top[son[u]]=top[u];rev[seg[0]]=son[u];
dfs2(son[u]);
}
for(int i=0;i<G[u].size();++i){
int v=G[u][i];
if(!top[v]){
seg[v]=++seg[0];top[v]=v;rev[seg[0]]=v;
dfs2(v);
}
}
}
inline void merge(int p){
sum[p]=sum[lc]+sum[rc];
cl[p]=cl[lc];cr[p]=cr[rc];
if(cr[lc]==cl[rc])--sum[p];
}
void build(int p,int l,int r){
if(l==r){
sum[p]=1;
cl[p]=cr[p]=num[rev[l]];
return;
}
int mid=(l+r)>>1;
build(lc,l,mid);
build(rc,mid+1,r);
merge(p);
}
inline void pass(int p){
if(laz[p]){
sum[lc]=sum[rc]=1;
cl[lc]=cl[rc]=cr[lc]=cr[rc]=laz[p];
laz[lc]=laz[rc]=laz[p];
}
laz[p]=0;
}
void change(int p,int l,int r,int ql,int qr,int k){
if(l>=ql&&r<=qr){
sum[p]=1;
cl[p]=cr[p]=k;
laz[p]=k;
return;
}
pass(p);
int mid=(l+r)>>1;
if(qr<=mid) change(lc,l,mid,ql,qr,k);
else if(ql>mid) change(rc,mid+1,r,ql,qr,k);
else{
change(lc,l,mid,ql,qr,k);change(rc,mid+1,r,ql,qr,k);
}
merge(p);
}
pi query(int p,int l,int r,int ql,int qr){
if(l>=ql&&r<=qr){
return (pi){sum[p],cl[p],cr[p]};
}
pass(p);
int mid=(l+r)>>1;
if(qr<=mid)return query(lc,l,mid,ql,qr);
else if(ql>mid) return query(rc,mid+1,r,ql,qr);
else{
return mergep(query(lc,l,mid,ql,qr),query(rc,mid+1,r,ql,qr));
}
}
int answer(int x,int y){
pi t;int ret=0;
int fx=top[x],fy=top[y];
int xcl=0,ycl=0;
while(fx!=fy){
if(dep[fx]<dep[fy])swap(x,y),swap(fx,fy),swap(xcl,ycl);
t=query(1,1,seg[0],seg[fx],seg[x]);
if(t.cr==xcl)--t.s;
ret+=t.s;xcl=t.cl;
x=fa[fx];
fx=top[x];
}
if(dep[x]>dep[y])swap(x,y),swap(xcl,ycl);
t=query(1,1,seg[0],seg[x],seg[y]);
if(xcl==t.cl)--t.s;
if(ycl==t.cr)--t.s;
return ret+t.s;
}
void act(int x,int y,int k){
int fx=top[x],fy=top[y];
while(fx!=fy){
if(dep[fx]<dep[fy])swap(x,y),swap(fx,fy);
change(1,1,seg[0],seg[fx],seg[x],k);
x=fa[fx];//跳过一条轻边
fx=top[x];
}
if(dep[x]>dep[y])swap(x,y);
change(1,1,seg[0],seg[x],seg[y],k);
}
char s;
signed main (){
sf("%d%d",&n,&m);for(int i=1;i<=n;++i)sf("%d",&num[i]);
for(int i=2;i<=n;++i){
int a,b;sf("%d%d",&a,&b);
G[a].push_back(b);G[b].push_back(a);
}
top[1]=seg[1]=rev[1]=seg[0]=1;
dfs1(1,0);dfs2(1);build(1,1,seg[0]);
while(m--){
int a,b,c;sf("\n%c%d%d",&s,&a,&b);
if(s=='Q')printf("%d\n",answer(a,b));
else{
sf("%d",&c);act(a,b,c);
}
}
return 0;
}