P2486 [SDOI2011]染色

题目链接

P2486 [SDOI2011]染色

给定一棵 \(n\) 个节点的无根树,共有 \(m\) 个操作,操作分为两种:

  1. 将节点 \(a\) 到节点 \(b\) 的路径上的所有点 (包括 \(a\)\(b\) ) 都染成颜色 \(c\)
  2. 询问节点 \(a\) 到节点 \(b\) 的路径上的颜色段数量。

颜色段的定义是极长的连续相同颜色被认为是一段。例如 112221 由三段组成:112221

输入格式

输入的第一行是用空格隔开的两个整数,分别代表树的节点个数 \(n\) 和操作个数 \(m\)
第二行有 \(n\) 个用空格隔开的整数,第 \(i\) 个整数 \(w_{i}\) 代表结点 \(i\) 的初始颜色。
\(3\) 到第 \((n+1)\) 行,每行两个用空格隔开的整数 \(u, v\) ,代表树上存在一条连结节点 \(u\) 和节点 \(v\) 的边。
\((n+2)\) 到第 \((n+m+1)\) 行,每行描述一个操作,其格式为:
每行首先有一个字符 \(o p\) ,代表本次操作的类型。

  • \(o p\)C ,则代表本次操作是一次染色操作,在一个空格后有三个用空格隔开的整数 \(a, b, c\) ,代表将 \(a\)\(b\) 的路径上所有点都染成颜色 \(c_{\text {。 }}\)
  • \(o p\)Q,则代表本次操作是一次查询操作,在一个空格后有两个用空格隔开的整数 \(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

说明/提示

数据规模与约定

对于 \(100 \%\) 的数据, \(1 \leq n, m \leq 10^{5} , 1 \leq w_{i}, c \leq 10^{9} , 1 \leq a, b, u, v \leq n\)\(op\)一定为 \(\mathrm{C}\)\(Q\) , 保证给出的图是一棵树。

解题思路

树链剖分

利用树链剖分思想将问题转换为一段连续区间上的操作,即统计区间上颜色段的数量,对于一段区间来说,先分为左右部分,统计左右部分颜色段的数量之和,如果左部分和右部分中间的颜色一样则说明该颜色段重复计算了,减一即可,所以线段树中应该存储的信息有 区间颜色段区间左边颜色区间右边颜色,但由于自上而下更新时如果当前区间完全在修改区间内,这时会直接返回,下面范围更小的区间还没有更新,所以需要打懒标记。另外树链剖分形成的区间可能是多段,段与段之间也可能出现相同颜色,这时也会重复,查询时记录两边相邻的颜色,最后处理哪一段判断相应的颜色是否相等即可

  • 时间复杂度:\(O((n+m)\times logn)\)

代码

// Problem: P2486 [SDOI2011]染色
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/P2486
// Memory Limit: 125 MB
// Time Limit: 1000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

// %%%Skyqwq
#include <bits/stdc++.h>
 
//#define int long long
#define help {cin.tie(NULL); cout.tie(NULL);}
#define pb push_back
#define fi first
#define se second
#define mkp make_pair
using namespace std;
 
typedef long long LL;
typedef pair<int, int> PII;
typedef pair<LL, LL> PLL;
 
template <typename T> bool chkMax(T &x, T y) { return (y > x) ? x = y, 1 : 0; }
template <typename T> bool chkMin(T &x, T y) { return (y < x) ? x = y, 1 : 0; }
 
template <typename T> void inline read(T &x) {
    int f = 1; x = 0; char s = getchar();
    while (s < '0' || s > '9') { if (s == '-') f = -1; s = getchar(); }
    while (s <= '9' && s >= '0') x = x * 10 + (s ^ 48), s = getchar();
    x *= f;
}

const int N=1e5+5;
int n,m,c[N],nc[N],id[N],cnt,sz[N],fa[N],dep[N],son[N],top[N];
vector<int> adj[N];
struct T
{
	int l,r;
	int lc,rc,sum,col;
}tr[N<<2];
void pushup(int u)
{
	tr[u].sum=tr[u<<1].sum+tr[u<<1|1].sum;
	if(tr[u<<1].rc==tr[u<<1|1].lc)tr[u].sum--;
	tr[u].lc=tr[u<<1].lc;
	tr[u].rc=tr[u<<1|1].rc;
}
void pushdown(int u)
{
	if(tr[u].col)
	{
		tr[u<<1].lc=tr[u<<1].rc=tr[u<<1|1].lc=tr[u<<1|1].rc=tr[u].col;
		tr[u<<1].col=tr[u<<1|1].col=tr[u].col;
		tr[u<<1].sum=tr[u<<1|1].sum=1;
		tr[u].col=0;
	}
}
void build(int u,int l,int r)
{
	tr[u]={l,r};
	if(l==r)
	{
		tr[u].lc=tr[u].rc=nc[l];
		tr[u].sum=1;
		return ;
	}
	int mid=l+r>>1;
	build(u<<1,l,mid);
	build(u<<1|1,mid+1,r);
	pushup(u);
}

void update(int u,int l,int r,int d)
{
	if(l<=tr[u].l&&tr[u].r<=r)
	{
		tr[u].lc=tr[u].rc=tr[u].col=d;
		tr[u].sum=1;
		return ;
	}
	pushdown(u);
	int mid=tr[u].l+tr[u].r>>1;
	if(l<=mid)update(u<<1,l,r,d);
	if(r>mid)update(u<<1|1,l,r,d);
	pushup(u);
}
T ask(int u,int l,int r)
{
	if(l<=tr[u].l&&tr[u].r<=r)return tr[u];
	int mid=tr[u].l+tr[u].r>>1;
	pushdown(u);
	if(l<=mid&&r>mid)
	{
		T res;
		T L=ask(u<<1,l,r),R=ask(u<<1|1,l,r);
		res.sum=L.sum+R.sum;
		res.lc=L.lc,res.rc=R.rc;
		if(L.rc==R.lc)
			res.sum--;
		return res;
	}
	if(l<=mid)return ask(u<<1,l,r);
	return ask(u<<1|1,l,r);
}
void update_path(int x,int y,int d)
{
	while(top[x]!=top[y])
	{
		if(dep[top[x]]<dep[top[y]])swap(x,y);
		update(1,id[top[x]],id[x],d);
		x=fa[top[x]];
	}
	if(dep[x]<dep[y])swap(x,y);
	update(1,id[y],id[x],d);
}
int ask_path(int x,int y)
{
	int res=0,lx=0,ly=0;
	while(top[x]!=top[y])
	{
		if(dep[top[x]]<dep[top[y]])swap(x,y),swap(lx,ly);
		T t=ask(1,id[top[x]],id[x]);
		res+=t.sum;
		if(t.rc==lx)res--;
		lx=t.lc;
		x=fa[top[x]];
	}
	if(dep[x]>dep[y])swap(x,y),swap(lx,ly);
	T t=ask(1,id[x],id[y]);
	res+=t.sum;
	if(t.lc==lx)res--;
	if(t.rc==ly)res--;
	return res;
}
void dfs1(int x,int father,int depth)
{
	fa[x]=father,sz[x]=1,dep[x]=depth;
	for(int y:adj[x])
	{
		if(y==father)continue;
		dfs1(y,x,depth+1);
		sz[x]+=sz[y];
		if(sz[son[x]]<sz[y])son[x]=y;
	}
}
void dfs2(int x,int t)
{
	id[x]=++cnt,nc[cnt]=c[x],top[x]=t;
	if(!son[x])return ;
	dfs2(son[x],t);
	for(int y:adj[x])
	{
		if(y==fa[x]||y==son[x])continue;
		dfs2(y,y);
	}
}

int main()
{
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++)scanf("%d",&c[i]);
	for(int i=1;i<n;i++)
	{
		int x,y;
		scanf("%d%d",&x,&y);
		adj[x].pb(y),adj[y].pb(x);
	}    
	dfs1(1,1,1);
	dfs2(1,1);
	build(1,1,n);
	while(m--)
	{
		char op[2];
		int a,b,c;
		scanf("%s%d%d",op,&a,&b);
		if(*op=='C')
		{
			scanf("%d",&c);
			update_path(a,b,c);
		}
		else
			printf("%d\n",ask_path(a,b));
	}
    return 0;
}
posted @ 2022-05-09 16:22  zyy2001  阅读(36)  评论(0编辑  收藏  举报