bzoj 2243:[SDOI2011]染色 树链剖分

本文介绍了一种利用树链剖分和线段树解决特定树形结构问题的方法,通过维护区间颜色信息,实现高效染色及查询路径上颜色段数量的功能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Description

给定一棵有n个节点的无根树和m个操作,操作有2类:
1、将节点a到节点b路径上所有点都染成颜色c;
2、询问节点a到节点b路径上的颜色段数量(连续相同颜色被认为是同一段),
如“112221”由3段组成:“11”、“222”和“1”。
请你写一个程序依次完成这m个操作。

Input

第一行包含2个整数n和m,分别表示节点数和操作数;
第二行包含n个正整数表示n个节点的初始颜色
下面 行每行包含两个整数x和y,表示x和y之间有一条无向边。
下面 行每行描述一个操作:
“C a b c”表示这是一个染色操作,把节点a到节点b路径上所有点(包括a和b)都染成颜色c;
“Q a b”表示这是一个询问操作,询问节点a到节点b(包括a和b)路径上的颜色段数量。

Output

对于每个询问操作,输出一行答案。


        既然是关于路径的那么直接去想树链剖分没跑了。

        如何快速的统计一个区间以及对一个区间进行合并呢,我们需要在线段树上维护三个信息,第一个是这个区间有多少种不同的颜色,另外两个就是两边分别是什么颜色,这样如果颜色相同,两个区间合并时就是两个区间个数加和-1,否则就是两个区间不同颜色个数加和了。

        对于染色,在染色的时候树链剖分时相当于执行线段树的区间赋值操作即可。

        对于查询时要稍微注意一下细节,由于我们树链剖分时,两个点都在向上走,且此时不能将两个答案合并,所以我们要先对两边分别计算当前答案,最后合并。由于底层的dfs序大,所以向上时在与新的答案合并的时候,要将原来的答案左边与新的答案的右边进行比较,来更新新的答案,如果写了合并函数,就等同于将原答案放在合并函数的右边。在最后两个答案在一条链上之时,我们先将两个点之间的区间,用上述方法和相对在底下的区间进行合并,得到ans1,相对较高的点已经得到的答案为ans2,那么此时两个区间的左端点是在一块的,所以按上述合并方法判断两个左端点颜色是否相同即可。讲的没有画的好,建议自己手推一下非常明白的。

        下附AC代码

#include<iostream>
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<vector>
#define maxn 100005
#define lson (now<<1)
#define rson ((now<<1)|1)
#define mid ((nl+nr)>>1)
using namespace std;
//以下为基本数组 
struct nod
{
	int sum,l,r;
	nod()
	{
		sum=0;
		l=-1;
		r=-1;
	}
};
nod bing(nod a,nod b)
{
	nod ans;
	ans.l=a.l;
	ans.r=b.r;
	ans.sum=a.sum+b.sum;
	if(a.r==b.l)
	ans.sum--;
	return ans;
}
int n,m;
int tt[maxn];
char s[20];
//以下为线段树 
nod dat[maxn<<2];
int lazy[maxn<<2]; 
void pushup(int now)
{
	dat[now]=bing(dat[lson],dat[rson]);
	return;
}
void pushdown(int now)
{
	if(lazy[now]!=-1)
	{
		dat[lson].sum=1;
		dat[rson].sum=1;
		dat[lson].l=dat[lson].r=dat[rson].l=dat[rson].r=lazy[now];
		lazy[lson]=lazy[now];
		lazy[rson]=lazy[now];
		lazy[now]=-1;
	}
	return;
}
void update(int ql,int qr,int col,int nl,int nr,int now)
{
	if(ql<=nl && nr<=qr)
	{
		dat[now].sum=1;
		dat[now].l=dat[now].r=col;
		lazy[now]=col;
		return;
	}
	pushdown(now);
	if(ql<=mid) update(ql,qr,col,nl,mid,lson);
	if(mid<qr)  update(ql,qr,col,mid+1,nr,rson);
	pushup(now);
}
nod query(int ql,int qr,int nl,int nr,int now)
{
	if(ql<=nl && nr<=qr)
	{
		return dat[now];
	}
	nod ans;
	pushdown(now);
	int flag1=0,flag2=0;
	nod temp1,temp2;
	if(ql<=mid)
	{
		temp1=query(ql,qr,nl,mid,lson);
		flag1=1;
	}
	if(mid<qr)
	{
		temp2=query(ql,qr,mid+1,nr,rson);
		flag2=1;
	}
	pushup(now);
	if(flag1==1 && flag2==1)
	return bing(temp1,temp2);
	if(flag1==1)
	return temp1;
	return temp2;
}
//以下为树链剖分
int cnt;
int dfn[maxn];
vector<int>edge[maxn];
int fa[maxn],anc[maxn],siz[maxn],dep[maxn];
void dfs1(int now,int pa)
{
	int len=edge[now].size();
	siz[now]=1;
	fa[now]=pa;
	for(int i=0;i<len;i++)
	{
		int nex=edge[now][i];
		if(nex!=pa)
		{
			dep[nex]=dep[now]+1;
			dfs1(nex,now);
			siz[now]+=siz[nex];
		}
	}
}
void dfs2(int now,int top)
{
	dfn[now]=++cnt;
	anc[now]=top;
	int len=edge[now].size();
	int son=0;
	for(int i=0;i<len;i++)
	{
		int nex=edge[now][i];
		if(siz[nex]>siz[son] && nex!=fa[now])
		{
			son=nex;
		}
	}
	if(son!=0)
	dfs2(son,top);
	for(int i=0;i<len;i++)
	{
		int nex=edge[now][i];
		if(nex!=son && nex!=fa[now])
		{
			dfs2(nex,nex);
		}
	}
}
void update(int p,int q,int col)
{
	int f1=anc[p],f2=anc[q];
	while(f1!=f2)
	{
		if(dep[f1]>=dep[f2])
		{
			update(dfn[f1],dfn[p],col,1,n,1);
			p=fa[f1];
		}
		else
		{
			update(dfn[f2],dfn[q],col,1,n,1);
			q=fa[f2];
		}
		f1=anc[p];f2=anc[q];
	}
	if(dfn[p]>dfn[q]) swap(p,q);
	update(dfn[p],dfn[q],col,1,n,1);
}
int query(int p,int q)
{
	nod ans1=query(dfn[p],dfn[p],1,n,1),ans2=query(dfn[q],dfn[q],1,n,1);
	int f1=anc[p],f2=anc[q];
	while(f1!=f2)
	{
		if(dep[f1]>=dep[f2])
		{
			nod now=query(dfn[f1],dfn[p],1,n,1);
			ans1=bing(now,ans1);
			p=fa[f1];
		}
		else
		{
			nod now=query(dfn[f2],dfn[q],1,n,1);
			ans2=bing(now,ans2);
			q=fa[f2];
		}
		f1=anc[p];f2=anc[q];
	}
	if(dfn[p]>dfn[q]) 
	{
		swap(p,q);
		swap(ans1,ans2);
	}
	nod now=query(dfn[p],dfn[q],1,n,1);
	ans2=bing(now,ans2);
	return ans1.sum+ans2.sum-(ans1.l==ans2.l);
}
int main()
{
	memset(lazy,-1,sizeof(lazy));
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++)
	{
		scanf("%d",&tt[i]);
	}
	for(int i=1;i<n;i++)
	{
		int x,y;
		scanf("%d%d",&x,&y);
		edge[x].push_back(y);
		edge[y].push_back(x);
	}
	dfs1(1,0);
	dfs2(1,1);
	for(int i=1;i<=n;i++)
	{
		update(dfn[i],dfn[i],tt[i],1,n,1);
	}
	while(m--)
	{
		scanf("%s",s);
		if(s[0]=='C')
		{
			int x,y,z;
			scanf("%d%d%d",&x,&y,&z);
			update(x,y,z);
		}
		else
		{
			int x,y;
			scanf("%d%d",&x,&y);
			printf("%d\n",query(x,y));
		}
	}
}


        

     



内容概要:本文档详细介绍了Analog Devices公司生产的AD8436真均方根-直流(RMS-to-DC)转换器的技术细节及其应用场景。AD8436由三个独立模块构成:轨到轨FET输入放大器、高动态范围均方根计算内核和精密轨到轨输出放大器。该器件不仅体积小巧、功耗低,而且具有广泛的输入电压范围和快速响应特性。文档涵盖了AD8436的工作原理、配置选项、外部组件选择(如电容)、增益调节、单电源供电、电流互感器配置、接地故障检测、三相电源监测等方面的内容。此外,还特别强调了PCB设计注意事项和误差源分析,旨在帮助工程师更好地理解和应用这款高性能的RMS-DC转换器。 适合人群:从事模拟电路设计的专业工程师和技术人员,尤其是那些需要精确测量交流电信号均方根值的应用开发者。 使用场景及目标:①用于工业自动化、医疗设备、电力监控等领域,实现对交流电压或电流的精准测量;②适用于手持式数字万用表及其他便携式仪器仪表,提供高效的单电源解决方案;③在电流互感器配置中,用于检测微小的电流变化,保障电气安全;④应用于三相电力系统监控,优化建立时间和转换精度。 其他说明:为了确保最佳性能,文档推荐使用高质量的电容器件,并给出了详细的PCB布局指导。同时提醒用户关注电介质吸收和泄漏电流等因素对测量准确性的影响。
内容概要:本文档介绍了一种基于ADP5070 DC-DC开关稳压器、ADP7142和ADP7182 CMOS LDO线性稳压器、LC滤波器及电阻分压器的电路设计方案,旨在为仅拥有5 V单电源的系统提供低噪声、双电源解决方案,以支持AD5761R双极性DAC的工作。AD5761R是一款16位双极性DAC,需要双电源来提供双极性输出电压范围。文中详细描述了如何配置该电路以适应单电源系统的应用,并展示了不同电源配置(包括外部电源、ADP5070和LC滤波器、ADP5070和LDO线性稳压器)下的性能测试结果,特别是频谱分析、输出电压噪声和交流性能等方面的数据。测试结果表明,增加LDO线性稳压器可以显著降低输出噪声,提升整体性能。 适合人群:从事精密仪器设计、数据采集系统开发的技术人员,尤其是那些需要理解和应用低噪声电源解决方案的专业人士。 使用场景及目标:适用于需要从单一5 V电源生成双电源的应用场合,如测试与测量设备、数据采集系统、执行器控制系统和工业自动化等领域。主要目标是在保证低噪声的前提下,确保AD5761R DAC能够在单电源环境中正常工作,提供高质量的双极性输出。 其他说明:本文档不仅提供了详细的电路配置指南,还通过大量的图表和数据分析验证了不同电源配置的效果。特别强调了在不同频率范围内,使用内部基准电压源和外部基准电压源(如ADR4525)对DAC输出噪声的影响。此外,文档还讨论了LC滤波器和LDO线性稳压器在减少开关纹波方面的作用,为实际应用提供了有价值的参考。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值