2020 CCPC长春 F. Strange Memory(dsu on tree+拆位算贡献)

博客介绍了如何使用DSU on Tree解决一种树形结构的问题,即计算满足特定条件的点权异或贡献。通过枚举根节点作为最低公共祖先(LCA),将问题转换为子树查询,并利用DSU维护子树信息。文章提到了在处理过程中需要注意的细节,如轻儿子的贡献统计和根节点特殊情况的处理,并提到可以采用拆位计算优化方法。

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

传送门

给定有根树 带点权 求出满足a[i] ^ a[j]=a[lca]的点 i^j 之和 。 点权<=1e6
我们考虑枚举根节点rt,求出当rt作为LCA时产生的贡献,相当于是枚举了LCA。

从而把问题转化成了子树查询问题,对于rt,能产生贡献的点对必顶位于rt不同孩子子树中,所以我们考虑dsu on tree,vector<int> num[i]表示点权为i的节点信息,最后保留重儿子信息。 对于每个轻儿子,先统计贡献,再更新num数组。

由于某棵子树删除影响后,vector<int> num[i]其实是空的状态,所以可以直接递归+pop_back 。

统计贡献直接枚举暴力统计…感觉时间复杂度很假,但是450ms就过了。也许是数据水了吧。

插言,已经是第二次遇到dsu on tree中枚举LCA作为根节点,计算孩子子树答案,计算完了再维护相关信息了。值得一提的是,这样的写法可能有坑,那就是当前根节点也许会产生贡献,这个要在他upd之前计算,虽然这题的根节点没有产生贡献,因为点权不会为0,异或结果不可能为LCA。

#include<bits/stdc++.h>
using namespace std;
//#pragma GCC optimize(2)
#define ull unsigned long long
#define ll long long
#define pii pair<int, int>
#define pdd pair<double, double>
#define re register
#define lc rt<<1
#define rc rt<<1|1
const int maxn = 1e5 + 10;
const ll mod = 998244353;
const ll inf = (ll)4e17+5;
const int INF = 1e9 + 7;
const double pi = acos(-1.0);
ll inv(ll b){
   if(b==1)return 1;return(mod-mod/b)*inv(mod%b)%mod;}
//给定有根树 带点权 求出满足a[i]^a[j]=a[lca]的点 i^j 之和
//转化成每个子树中查询答案 累加起来 (树根就是LCA 也就相当于枚举LCA了)
//对于节点u 枚举num[a[lca]^a[u]]的每个节点 暴力统计
vector<int> num[maxn*20];
vector<int> g[maxn];
int n;
int a[maxn];
int in[maxn],pos[maxn],clk,son[maxn],siz[maxn],dep[maxn];
void dfs1(int rt,int fa)
{
   
	dep[rt]=dep[fa]+1;
	siz[rt]=1;
	in[rt]=++clk;
	pos[clk]=rt;
	for(int i:g[rt])
	{
   
		if(i==fa) continue;
		dfs1(i,rt);
		siz
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值