cf 600E/570D DSU on the tree 树上启发式合并

本文介绍了两种高级的数据结构和算法概念:树形动态规划(Tree DP)与重链剖分(Heavy-Light Decomposition)。通过具体的代码实现,详细解析了如何利用这些技术高效地解决树状结构上的问题,例如查询子树属性、路径更新等。

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

学习学习

600E
板子

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=2e5+5;
int fa[N],son[N],siz[N];
struct Edge{
	int to,next;
	Edge(){}
	Edge(int to,int next):to(to),next(next){}
}E[N];
int head[N],tot;
inline void addedge(int u,int v){
	E[tot]=Edge(v,head[u]);
	head[u]=tot++;
}
void dfs(int x,int f){
	siz[x]=1,fa[x]=f;
	for(int i=head[x];~i;i=E[i].next)if(E[i].to^f){
		int v=E[i].to;
		dfs(v,x);
		siz[x]+=siz[v];
		if(siz[v]>siz[son[x]])son[x]=v;
	}
}
ll Ans[N],maxans,ans;
int cnt[N],vis[N],col[N];
void add(int x,int p){
	cnt[col[x]]+=p;
	if(p>0&&cnt[col[x]]==maxans)ans+=col[x];
	if(p>0&&cnt[col[x]]>maxans)maxans=cnt[col[x]],ans=col[x];
	for(int i=head[x];~i;i=E[i].next)if(E[i].to^fa[x]&&!vis[E[i].to])add(E[i].to,p);
	// !vis[E[i].to]就再遍历一遍轻儿子
}
void dfs2(int x,int p){//x子树根节点,p表示x是否是重儿子
	for(int i=head[x];~i;i=E[i].next){
		int v=E[i].to;
		if(v^fa[x]&&v^son[x])dfs2(v,0);//遍历轻儿子
	}
	if(son[x])dfs2(son[x],1),vis[son[x]]=1;//遍历重儿子
	add(x,1),Ans[x]=ans;//计算子树
	if(son[x])vis[son[x]]=0;
	if(!p)add(x,-1),ans=maxans=0;//是轻儿子,擦除
}
void init(){
	tot=0,memset(head,-1,sizeof(head));
}
int n,u,v;
int main(){
	init();
	scanf("%d",&n);
	for(int i=1;i<=n;++i)scanf("%d",&col[i]);
	for(int i=1;i< n;++i)scanf("%d%d",&u,&v),addedge(u,v),addedge(v,u);
	dfs(1,0),dfs2(1,0);
	for(int i=1;i<=n;++i)printf("%lld ",Ans[i]);
	return 0;
}

570D

#include<bits/stdc++.h>
#define P(i,j) make_pair(i,j)
using namespace std;
typedef long long ll;
const int N=5e5+5;
int fa[N],son[N],siz[N],dep[N];
struct Edge{
	int to,next;
	Edge(){}
	Edge(int to,int next):to(to),next(next){}
}E[N<<2];
int head[N],tot;
inline void addedge(int u,int v){
	E[tot]=Edge(v,head[u]);
	head[u]=tot++;
}
void dfs(int x,int f,int d){
	siz[x]=1,fa[x]=f,dep[x]=d;
	for(int i=head[x];~i;i=E[i].next)if(E[i].to^f){
		int v=E[i].to;
		dfs(v,x,d+1);
		siz[x]+=siz[v];
		if(siz[v]>siz[son[x]])son[x]=v;
	}
}
int cnt[N],col[N],vis[N],ans[N];
char s[N];
vector<pair<int,int> >query[N];
bool C(int x){//二进制几个1
	x=(x&0x55555555)+((x&0xaaaaaaaa)>>1);
	x=(x&0x33333333)+((x&0xcccccccc)>>2);
	x=(x&0x0f0f0f0f)+((x&0xf0f0f0f0)>>4);
	x=(x&0x00ff00ff)+((x&0xff00ff00)>>8);
	x=(x&0x0000ffff)+((x&0xffff0000)>>16);
	return x<=1;
}
void add(int x){//两次异或刚好消除影响
	cnt[dep[x]]^=1<<(s[x]-'a');
	for(int i=head[x];~i;i=E[i].next)if(E[i].to^fa[x]&&!vis[E[i].to])add(E[i].to);
}
void dfs2(int x,int p){
	for(int i=head[x];~i;i=E[i].next){
		int v=E[i].to;
		if(v^fa[x]&&v^son[x])dfs2(v,0);
	}
	if(son[x])dfs2(son[x],1),vis[son[x]]=1;
	add(x);
	for(auto i:query[x])ans[i.second]=C(cnt[i.first]);
	if(son[x])vis[son[x]]=0;
	if(!p)add(x);
}
void init(){
	tot=0,memset(head,-1,sizeof(head));
}
int n,u,v,m;
int main(){
	init();
	scanf("%d%d",&n,&m);
	for(int i=2;i<=n;++i)scanf("%d",&v),addedge(v,i),addedge(i,v);
	scanf("%s",s+1);
	for(int i=1;i<=m;++i)scanf("%d%d",&u,&v),query[u].push_back(P(v,i));
	dfs(1,0,1),dfs2(1,0);
	for(int i=1;i<=m;++i)puts(ans[i]?"Yes":"No");
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值