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

22 篇文章 0 订阅
21 篇文章 0 订阅

学习学习

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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值