首页 > 其他分享 >染色

染色

时间:2024-05-17 15:58:13浏览次数:19  
标签:rt 颜色 int 染色 ans rid op

[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)\) 行,每行描述一个操作,其格式为:

每行首先有一个字符 \(op\),代表本次操作的类型。

  • 若 \(op\) 为 C,则代表本次操作是一次染色操作,在一个空格后有三个用空格隔开的整数 \(a, b, c\),代表将 \(a\) 到 \(b\) 的路径上所有点都染成颜色 \(c\)。
  • 若 \(op\) 为 Q,则代表本次操作是一次查询操作,在一个空格后有两个用空格隔开的整数 \(a, b\),表示查询 \(a\) 到 \(b\) 路径上的颜色段数量。

输出格式

对于每次查询操作,输出一行一个整数代表答案。

样例 #1

样例输入 #1

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

样例输出 #1

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\) 一定为 CQ,保证给出的图是一棵树。

除原数据外,还存在一组不计分的 hack 数据。

这题让我想到了山海经,这道题用树链剖分,记录每个区间左端点和右端点的颜色,如果左孩子的右区间=右孩子的左区间,那么答案需要减1,注意容易遗漏一点,就是树链剖分的时候我们是一条一条的链
当然不能自然地把路径上的颜色带累加
我们发现树剖求LCA是利用两个点按照深度向上跳最后跳到一起的方法
自下而上,根据深度交替向上跳
而这个路径可以看成‘人’字型

我们不妨把这个路径分成两边左边和右边我们再用变量
pos1表示当前要往上跳的路径\上次的终点颜色(值得注意的是,终点是左端点的颜色,因为dfs序从小到大连续的,根节点是较小的点)
pos2表示另一条路径\上一次的终点颜色
这样,如果当前往上跳的路径\这次的起点颜色等于 当前要往上跳的路径\上次的终点颜色 那么颜色段数量-1
还有最后的时候,top[u]=top[v]的时候,即已经在同一个重链上时,两边端点颜色都要考虑与对应ans比较颜色,相同答案要相应减一

点击查看代码
#include <bits/stdc++.h>
#define ll long long
#define register int int
#define lid (rt<<1)
#define rid (rt<<1|1)
using namespace std;
const int N = 1e6+5; 
int n,m;
struct Tree
{
	int l,r,lz;ll lc,rc,cnt;
}st[N<<4];
struct ac
{
	int u,to,next;
}edge[N*2];
int cnt=1,head[N];
void add(int u,int v)
{
	edge[++cnt].u=u;
	edge[cnt].to=v;
//	edge[cnt].w=w;
	edge[cnt].next=head[u];
	head[u]=cnt;
}
int dep[N],fa[N],top[N],ntime,dfn[N],size[N],son[N],rnk[N];ll w[N];
void _pushup(int rt)
{
	if(st[lid].rc==st[rid].lc)
	{
		st[rt].cnt=st[lid].cnt+st[rid].cnt-1;
	}else st[rt].cnt=st[lid].cnt+st[rid].cnt;
	st[rt].lc=st[lid].lc;
	st[rt].rc=st[rid].rc;
//	cout<<"%%"<<rt<<" "<<lid<<" "<<rid<<" "<<st[rt].lc<<" "<<st[rt].rc<<endl;	
}
inline Tree pushup(Tree x,Tree y)
{
	Tree z={0,0,0};
	if(!y.cnt)
	{
		z.l=x.l;z.r=x.r;
		z.cnt=x.cnt;
		z.lc=x.lc;
		z.rc=x.rc;
		return z;
	}
	if(!x.cnt)
	{
		z.l=y.l;z.r=y.r;
		z.cnt=y.cnt;
		z.lc=y.lc;
		z.rc=y.rc;
		return z;		
	}
	if(x.rc==y.lc)
	{
		z.cnt=x.cnt+y.cnt-1;
	}else z.cnt=x.cnt+y.cnt;
	z.lc=x.lc;
	z.rc=y.rc;
	z.l=x.l;z.r=y.r;
	return z;
}
inline void pushson(int rt,int col)
{
	if(st[lid].cnt)
	{
		st[lid].lz=st[lid].lc=st[lid].rc=col;
		st[lid].cnt=1;
	}
	if(st[rid].cnt)
	{
		st[rid].lz=st[rid].lc=st[rid].rc=col;
		st[rid].cnt=1;
	}	
}
inline void pushdown(int rt)
{
	if(st[rt].lz)
	{
		int lz=st[rt].lz;st[rt].lz=0;
		st[rt].cnt=1;
		pushson(rt,lz);
	}
}
//void pushcol(int rt,int col) {
//    st[rt].lc=st[rt].rc=col;
//    st[rt].cnt=1,st[rt].lz=col;
//}
//void pushdown(int rt) {
//    if(st[rt].lz) {
//        if(lid) pushcol(lid,st[rt].lz);
//        if(rid) pushcol(rid,st[rt].lz);
//        st[rt].lz=0;
//    }
//}
void bt(int rt,int l,int r)
{
	st[rt].l=l;st[rt].r=r;
	if(l==r)
	{
		st[rt].lc=st[rt].rc=w[rnk[l]];
		st[rt].cnt=1;
		return;
	}
	int mid=(l+r)>>1;
	bt(lid,l,mid);
	bt(rid,mid+1,r);
	st[rt]=pushup(st[lid],st[rid]);
//	_pushup(rt);
//	cout<<rt<<" "<<l<<" "<<r<<" "<<st[rt].cnt<<endl;
}
int rl,rr,pos1,pos2;
int query(int rt,int l,int r)
{

	if(l<=st[rt].l&&st[rt].r<=r)
	{
		if(st[rt].l==l)rl=st[rt].lc;
		if(st[rt].r==r)rr=st[rt].rc;
		return st[rt].cnt;
	}
	int mid=(st[rt].l+st[rt].r)>>1;
	int ans=0;
	pushdown(rt);
	if(r<=mid)return query(lid,l,r);
	if(l>mid)return query(rid,l,r);
	ans=query(lid,l,r)+query(rid,l,r);
//	if(l<=mid)ans+=query(lid,l,r);
//	if(r>mid)ans+=query(rid,l,r);
//	cout<<rt<<" "<<l<<" "<<r<<" "<<ans<<endl;
	if(l<=mid&&r>mid&&st[lid].rc==st[rid].lc)ans--;
	return ans;
}
void update(int rt,int l,int r,int val)
{
	if(l<=st[rt].l&&st[rt].r<=r)
	{
		st[rt].lc=st[rt].rc=val;
		st[rt].lz=val;
		st[rt].cnt=1;
//		pushcol(rt,val);
		return;
	}
	int mid=(st[rt].l+st[rt].r)>>1;
	pushdown(rt);
//	cout<<"##"<<rt<<" "<<st[rt].l<<" "<<st[rt].r<<" "<<st[rt].cnt<<endl;
	if(l<=mid)update(lid,l,r,val);
	if(r>mid) update(rid,l,r,val);
	st[rt]=pushup(st[lid],st[rid]);
//	_pushup(rt);
	return;	
}

void find(int u,int _fa,int depth)
{
	fa[u]=_fa;
	dep[u]=depth;
	son[u]=0;
	size[u]=1;
	int ms=0;
	for(int i=head[u];i;i=edge[i].next)
	{
		int to=edge[i].to;
		if(to==_fa)continue;
		if(dep[to])continue;
		find(to,u,depth+1);
		size[u]+=size[to];
		if(ms<size[to])
		{
			ms=size[to];
			son[u]=to;
		}
	}
}
void connect(int u,int acst)
{
	dfn[u]=++ntime;
	top[u]=acst;
	rnk[ntime]=u;
	if(son[u])
	{
		connect(son[u],acst);
	}
	for(int i=head[u];i;i=edge[i].next)
	{
		int to=edge[i].to;
		if(son[u]==to||to==fa[u])continue;
		connect(to,to);
	}
}
int Q(int l,int r)
{
	int ans=0;
	int tot=0;pos1=pos2=0;
	rl=rr=0;
	while(top[l]!=top[r])
	{
		if(dep[top[l]]<dep[top[r]])swap(l,r),swap(pos1,pos2);
		ans+=query(1,dfn[top[l]],dfn[l]);
		if(rr==pos1)tot++;
		l=fa[top[l]];pos1=rl;
	}
	if(dep[l]>dep[r])swap(l,r),swap(pos1,pos2);
	ans+=query(1,dfn[l],dfn[r]);
	if(rl==pos1)tot++;
	if(rr==pos2)tot++;
	return ans-tot;
}
void Qmodify(int l,int r,int c)
{
	while(top[l]!=top[r])
	{
		if(dep[top[l]]<dep[top[r]])swap(l,r);
//		cout<<"##"<<dfn[top[l]]<<" "<<dfn[l]<<endl;
		update(1,dfn[top[l]],dfn[l],c);
		l=fa[top[l]];
	}
	if(dep[l]>dep[r])swap(l,r);
	update(1,dfn[l],dfn[r],c);
}
int main()
{
//	ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
	cin>>n>>m;
	int a,b;
	for(int i=1;i<=n;i++)
	{
		cin>>w[i];
	}
	for(int i=1;i<n;i++)
	{
		cin>>a>>b;
		add(a,b);
		add(b,a);
	}
	find(1,0,1);
	connect(1,1);
	bt(1,1,n);
	int q;
	char op[5];
	for(int i=1;i<=m;i++)
	{
		cin>>op;
		if(op[0]=='C')
		{
			cin>>a>>b>>q;
			Qmodify(a,b,q);
		}else if(op[0]=='Q')
		{
			cin>>a>>b;
			cout<<Q(a,b)<<endl;			
		}
	}
	return 0;
}

标签:rt,颜色,int,染色,ans,rid,op
From: https://www.cnblogs.com/wlesq/p/18197905

相关文章

  • 二分图染色
    二分图booldfs(intu,intc){ if(color[u]==c) returntrue; elseif(color[u]==3-c) returnfalse; color[u]=c; for(intv:graph[u]) if(!dfs(v,3-c))returnfalse; returntrue;}习题:P1330封锁阳光大学解题思路按照题目要求,每一条......
  • 染色问题 题解
    \(f(i)\):满足\(n\)行\(m\)列每行每列都有颜色,最多用了\(j\)种颜色的方案数根据容斥原理\[f(i)=[(i+1)^m-1]^n-\sum_{i=1}^m(-1)^{k-1}C_m^k[(i+1)^{m-k}-1]^n\]意思是对于每一行,每个格子都可以填\(i\)种颜色或不填;但是整行不能一个格子都不填色,所以减一;而有\(n\)行,......
  • 贡献法和染色的妙用
    链接:https://ac.nowcoder.com/acm/contest/80259/E来源:牛客网时间限制:C/C++1秒,其他语言2秒空间限制:C/C++262144K,其他语言524288K64bitIOFormat:%lld题目描述小红拿到了一个n∗n的方格矩阵。她准备划分成若干个大小为3的'L'型连通块和若干个大小为4的2*2......
  • 棋盘进行黑白染色(java)
    【题目】 有一个n*m的棋盘,现在对这个棋盘进行黑白染色,左上角染成黑色。从左上角开始,每个黑色格的相邻格染成白色,白色格的相邻格染成黑色。以下给出了一个5*7的棋盘的染色示例。给定n和m,请问棋盘上一共有多少方格被染成了黑色。【代码】publicclassTest13{public......
  • 小美的树上染色(美团2024届秋招笔试第一场编程真题)
    题面核心思想树形DPdp[1]表示以当前节点为根节点所包含的子树且当前节点能染色的最大染色数量dp[0]表示以当前节点为根节点所包含的子树且当前节点不染色的最大染色数量详情看注释~代码importjava.util.*;publicclassMain{publicstaticvoidmain(String[......
  • maya给模型以及子节点随机染色
    maya给模型以及子节点随机染色 importrandomimportmaya.cmdsaspydefmaterial1():sel=py.ls(sl=True)ifsel!=[]:forobjinsel:myShade=py.shadingNode('lambert',asShader=True)#printmyShademyShad......
  • 非有序数组也能二分? —— 红蓝染色法续篇(Leetcode 162.寻找峰值)
    1.写在前面本文为个人学习总结,参考:B站Up:灵茶山艾府参考视频链接:https://www.bilibili.com/video/BV1QK411d76w/2.题目我们来看一下下面这道题:峰值元素是指其值严格大于左右相邻值的元素。给你一个整数数组nums,找到峰值元素并返回其索引。数组可能包含多个峰值,在......
  • 二分查找总结——二分查找细节分析 + 红蓝染色法
    1.写在前面本文为个人学习总结,二分算法参考:B站Up:灵茶山艾府(二分查找红蓝染色法)视频链接:https://www.bilibili.com/video/BV1AP41137w7/Leetcode题目:34.在排序数组中查找元素的第一个和最后一个位置给你一个按照非递减顺序排列的整数数组nums,和一个目标值target。请你......
  • 24/02/21 染色问题
    题目描述给定一棵\(n\)个节点的树,你想把编号为\(i\)的叶子节点染成\(a_i\)的颜色。你本来可以一个节点一个节点的涂,但你觉得这样太慢了,你决定这样染色:选择一个节点\(x\)和一种颜色\(c\),然后把这个颜色的颜料桶直接倒在节点\(x\)上,使\(x\)的所有子树都染成\(c\)......
  • 环形染色问题
    一个大小为\(n\)的圆环(环上的点有编号)需要用\(m\)种颜色进行染色(每种颜色不必全都使用),要求相邻两个点的的颜色不同,有多少种染色方案?为了不考虑边界问题,假定\(n,m\ge2\)。如果不考虑这是一个环,当成一条链,那么第\(1\)个点颜色任意,其他所有点都只需要满足和前面那个点颜色相......