#2134 染色 【树链剖分】

版权声明:----------------------------------------转载是ok的,但要附上出处哟 https://blog.csdn.net/qq_43040655/article/details/87286818

描述

给定一棵有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;
}


猜你喜欢

转载自blog.csdn.net/qq_43040655/article/details/87286818