首页 > 其他分享 >[DS记录] P6623 [省选联考 2020 A 卷] 树

[DS记录] P6623 [省选联考 2020 A 卷] 树

时间:2023-08-29 20:11:31浏览次数:43  
标签:rt ch 省选 siz P6623 dat int rm 联考

题目传送门

\(\rm Trie\) 树的一些牛逼应用

异或和是可以用 \(\rm 01-Trie\) 维护的。我们发现对于一个点 \(x\),需要需要维护 \(x\) 子树的所有点的异或和,这可以理解成 \(\rm Trie\) 树的合并。同时有一个 \(d(y,x)\) 的存在,其实考虑 \(\rm dfs\) 的过程,相当于先合并所有子节点的 \(\rm Trie\) 树后,对所有数 \(+1\)。再插入 \(val_x\)

因此,我们的 \(\rm Trie\) 树需要有以下的功能:

  • 维护异或和

  • 插入一个数

  • 合并两个子树

  • 整棵树所有的数 \(+1\)

前两个操作是基本的,将数从低位到高位插入,每个节点 \(p\) 维护 \(ch[p][2],siz[p],dat[p]\)。合并类似线段树合并。整棵树 \(+1\) 的操作其实相当于从低位到高位找第一个出现的 \(0\),然后把 \(0\) 变 \(1\),低位的 \(1\) 全部变 \(0\)。对应到字典树上相当于交换左右儿子,然后递归 \(ch[p][0]\)。注意因为有 \(+1\),所以会导致进位,因此我们在一开始插入一个数时就完整地插入 \(21\) 位,这样就不会溢出

#include<bits/stdc++.h>
#define LL long long
using namespace std;

const int N=525020,NN=21*525010+10,M=21;

int n,val[N],rt[N],tot;
int ch[NN][2],dat[NN],siz[NN];
LL ans;
vector <int> g[N];

void maintain(int p)
{
	dat[p]=siz[p]=0;
	if(ch[p][0])
	{
		siz[p]+=siz[ch[p][0]];
		dat[p]^=dat[ch[p][0]]<<1;
	}
	if(ch[p][1])
	{
		siz[p]+=siz[ch[p][1]];
		dat[p]^=(dat[ch[p][1]]<<1)|(siz[ch[p][1]]&1);
	}
}

void insert(int &p,int v,int dep)
{
	if(!p)
		p=++tot;
	if(dep==M)
	{
		siz[p]++;
		return;
	}
	
	int t=v&1;
	insert(ch[p][t],v>>1,dep+1);
	maintain(p);
}

void add(int p)
{
	swap(ch[p][0],ch[p][1]);
	if(ch[p][0])
		add(ch[p][0]);
	maintain(p);
}

int merge(int p,int q)
{
	if(!p)
		return q;
	if(!q)
		return p;
	siz[p]+=siz[q];
	dat[p]^=dat[q];
	ch[p][0]=merge(ch[p][0],ch[q][0]);
	ch[p][1]=merge(ch[p][1],ch[q][1]);
	maintain(p);
	return p;
}

void dfs(int x)
{
	for(auto y:g[x])
	{
		dfs(y);
		rt[x]=merge(rt[x],rt[y]); 
	} 
	
	add(rt[x]);
	insert(rt[x],val[x],0);
	ans+=(LL)dat[rt[x]];
}

int main()
{	
	scanf("%d",&n);
	for(int i=1; i<=n; i++)
		scanf("%d",&val[i]);
	for(int i=2; i<=n; i++)
	{
		int fa;
		scanf("%d",&fa);
		g[fa].push_back(i);
	}
	
	dfs(1);
	
	printf("%lld",ans);
	
	return 0;
}

标签:rt,ch,省选,siz,P6623,dat,int,rm,联考
From: https://www.cnblogs.com/xishanmeigao/p/17665735.html

相关文章

  • [十二省联考 2019] 春节十二响
    题目链接。题意给出一棵有\(n\)个节点的树,要求你将集合\(\{1,2,\dots,n\}\)划分成若干个子集,使得没有子集拥有节点对满足两个元素在树上是祖孙关系。你需要最小化子集的最大值之和。先考虑带有启发性的子任务\(4\)(树是一颗链)。具体来说,树有以下两种形态:根节点是链的......
  • [九省联考 2018 D1T3] 秘密袭击
    考虑转化为求\(\gei\)的权值个数\(\gek\)的联通块数量。设\(f(u,i,j)\)表示\(u\)子树内含\(u\)联通块内权值\(\gei\)的有\(j\)个的方案数,\(g(u,i,j)\)维护子树的和,也就是最终答案。发现转移非常简单所以可以写成生成函数:\[F(u,i)=x^{[d_u\gei]}\prod_{(u,......
  • 洛谷 P6620 [省选联考 2020 A 卷] 组合数问题
    前置知识二项式定理\[(x+y)^n=\sum_{i=0}^n\binomnix^iy^{n-i}\]组合恒等式\[k\times\binomnk=n\times\binom{n-1}{k-1}\]题解先不管取模的事情。考虑把\(f(k)\)中次数相同的项拿出来,则原式可化为:\[Ans=a_0\sum_{k=0}^nx^k\times\binomnk......
  • SDFZ 8 月联考游记
    前言现在写的时候已经是\(\mathsf{15}\)号了。省流:\(100+100+100+100=400\)。Day0大颓,打原神+崩铁。崩铁刷出极品双爆衣,感觉明天会寄掉了。晚上随便刷点区间dp睡觉。Day1\(8:00\)到校,发现\(9:00\)才开考。清峥说会有矩阵乘法的题目,所以复习了一下。接下来就是......
  • 2023-08-14 CSP-J模拟联考 游记
    8:00 赶到 FZ,9:00正式开考。开考前先洗了一把脸。9:00~9:15开T1,原本没有思路,但后来想到可以贪心,每次找到<n 的最大的斐波那契数。于是打了个斐波那契的表,就过了。9:15~10:00T2写了45分钟我是什么东西。一开始想法是把每一个字符的数量统计起来,如果相差<1就满足要求,否......
  • 「题解注释」P7518 [省选联考 2021 A/B 卷] 宝石
    联合省选2021宝石题解-hezlik的博客-洛谷博客(luogu.com.cn)耗时:一晚上+半个上午代码注释:#include<bits/stdc++.h>usingnamespacestd;constintN=500000,C=21;intRi(){intx=0,y=1;charc=getchar();for(;c<'0'||c>'9';c=getchar())if......
  • 联合省选 2023 填数游戏
    这是22年的我:https://www.luogu.com.cn/record/81067862这是23年的我:看我一个流过冲过A性质首先考虑判定。一个经典模型是:如果在\(T_{i,0}\)与\(T_{i,1}\)之间连一条无向边(若\(|T_i|=1\)则认为\(T_{i,1}=T_{i,0}\)),那么题目转化为给每条边定向,使得每个点的入度不超......
  • [十二省联考 2019] 字符串问题
    题目描述现有一个字符串\(S\)。Tiffany将从中划出\(n_a\)个子串作为\(A\)类串,第\(i\)个(\(1\leqslanti\leqslantn_a\))为\(A_i=S(la_i,ra_i)\)。类似地,Yazid将划出\(n_b\)个子串作为\(B\)类串,第\(i\)个(\(1\leqslanti\leqslantn_b\))为\(B_i=S(lb_i,......
  • 省选前全部笔记
    观前提醒其实也不能说是笔记,以为你看看就知道了,好多更像是日记。可以试试去调错字,因为你能挑出100个我写错的字(不带夸张)主要是分享一下我当时的精神状态,希望处在低谷的oier们也不要灰心。学术内容可以略看,因为不少是扯淡。大部分英语是chinglish,图一乐就行至于我有没有入选......
  • 2023 联合省选-PKUSC2023-NOI2023游记
    在这段时间主要在学文化课,没怎么停课,天天暴力拼盘,所以索性合在一起。感觉非常意识流,和OI关系好像也不大。pig嫌我开始写的太短,我积极听取他人建议,加了一车流水账。联赛结束以后就退役了。因为即使NGOI也大概率会被卡“省线”,但还打算参加省选碰碰运气。遂在省选前两周申请一周半......