ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

Educational Codeforces Round 132 E,F

2022-07-23 11:06:27  阅读:191  来源: 互联网

标签:nxt Educational val fa int 路径 Codeforces pos 132


E

容易发现,我们在一个点进行修改,一定可以将经过这个点的非法路径数变成\(0\)。具体的方案就是将\(i\)异或上\(2^{p_{i}}\),其中\(p_{i}>30\),并且\(p\)要两两不同。(比如\(p_{i}=30+i\)就是一组可行的\(p\))

此时我们有一个贪心策略:为了让更多非法路径变成合法的,那么我们修改的点深度要尽可能小。

那么我们从叶子向根考虑:如果当前点\(p\),存在一个非法路径\((u,v)\),满足\(lca(u,v)=p\),那么我们一定修改\(p\),否则再往上就没有这条路径的点了,也无法让这条路径变成合法的了。

如何判断是否存在一个非法路径\((u,v)\),满足\(lca(u,v)=p\)呢?我们发现:设\(f(i)\)为从根到点\(i\)的路径的异或值,那么路径\((u,v)\)的权值异或和就等于\(f(u)\oplus f(v)\oplus a_{lca}\)。那么用\(S_{pos}\)存储当前子树的\(f\)的集合,在遇到一个儿子时,对于\(t\in S_{son}\),我们查询\(t\oplus a_{pos}\)是否在\(S_{pos}\)中出现过,如果有,那么意味着有一条异或和等于\(0\)的路径,其lca等于pos。最后再将\(S_{son}\)并入\(S_{pos}\)中即可。

注意修改\(p\)之后,我们不仅让\(lca=p\)的非法路径成为合法路径,同时还让所有经过\(p\)往根走的非法路径也变成合法的了。故如果我们要修改当前点\(p\),那么\(S_{p}\)需要清空。

具体代码如下:

void cnt(int pos,int fa=0) {
	int is=0;
	val[pos].insert(f[pos]);
	for(auto nxt : G[pos]) {
		if(nxt==fa) continue;
		cnt(nxt,pos);
		for(auto item : val[nxt]) {
			if(val[pos].find(item^a[pos])!=val[pos].end()) {
				is=1;
			}
		}
		val[pos].insert(val[nxt].begin(),val[nxt].end());
	}
	if(is) {
		ans++;
		val[pos].clear();
	}
}

但是这样时间复杂度有可能达到\(O(n^2\log n)\),因为将\(S_{son}\)并入\(S_{pos}\)中这个操作有可能是\(O(n \log n)\)的。如果我们采用启发式合并(将小的Set合并到大的Set中),那么时间复杂度将优化到\(O(n\log ^2 n)\)。

整体代码如下:

#include<bits/stdc++.h>
#define debug(...) std::cerr<<#__VA_ARGS__<<" : "<<__VA_ARGS__<<std::endl

const int maxn=200005;
int n,ans;
int a[maxn],f[maxn];
std::set<int> val[maxn];
std::vector<int> G[maxn];

void dfs(int pos,int fa=0) {
	f[pos]=f[fa]^a[pos];
	for(auto nxt : G[pos]) {
		if(nxt==fa) continue;
		dfs(nxt,pos);
	}
}

void cnt(int pos,int fa=0) {
	int is=0;
	val[pos].insert(f[pos]);
	for(auto nxt : G[pos]) {
		if(nxt==fa) continue;
		cnt(nxt,pos);
		if(val[pos].size()<val[nxt].size()) {
			std::swap(val[pos],val[nxt]);
		}
		for(auto item : val[nxt]) {
			if(val[pos].find(item^a[pos])!=val[pos].end()) {
				is=1;
			}
		}
		val[pos].insert(val[nxt].begin(),val[nxt].end());
	}
	if(is) {
		ans++;
		val[pos].clear();
	}
}

int main() {
	scanf("%d",&n);
	for(int i=1;i<=n;i++) {
		scanf("%d",&a[i]);
	}
	for(int i=1;i<=n-1;i++) {
		int x,y; scanf("%d%d",&x,&y);
		G[x].push_back(y);
		G[y].push_back(x);
	}
	dfs(1);	
	cnt(1);
	printf("%d\n",ans);
	return 0;
}

标签:nxt,Educational,val,fa,int,路径,Codeforces,pos,132
来源: https://www.cnblogs.com/Nastia/p/16511088.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有