P6623 [省选联考 2020 A 卷] 树

P6623 [省选联考 2020 A 卷] 树

题目描述

给定一棵 n 个结点的有根树 T,结点从 1 开始编号,根结点为 1 号结点,每个结点有一个正整数权值 vi

x 号结点的子树内(包含 x 自身)的所有结点编号为 c1,c2,,ck,定义 x 的价值为:

val(x)=(vc1+d(c1,x))(vc2+d(c2,x))(vck+d(ck,x))

其中 d(x,y) 表示树上 x 号结点与 y 号结点间唯一简单路径所包含的边数,d(x,x)=0 表示异或运算。

请你求出 i=1nval(i) 的结果。

输入格式

第一行一个正整数 n 表示树的大小。

第二行 n 个正整数表示 vi

接下来一行 n1 个正整数,依次表示 2 号结点到 n 号结点,每个结点的父亲编号 pi

输出格式

仅一行一个整数表示答案。

【数据范围】

对于 100% 的数据:1n,vi5250101pin

Solution:

好神的二进制题。

我们发现从祖先子树是不明智的,所以我们考虑刻画单点对于祖先的影响:

K val
0 001001
1 001010
2 001011
3 001100
4 001101
5 001110
6 001111
7 010000
8 010001
9 010010
10 010011
bit 0 1 2 3 4 5 6 7 8 9 10
0 1 0 1 0 1 0 1 0 1 0 1
1 0 1 1 0 0 1 1 0 0 1 1
2 0 0 0 1 1 1 1 0 0 0 0
3 1 1 1 1 1 1 0 0 0 0 0

打完这张表之后我们发现随着相对深度的上涨,一个点对其 k 级祖先在二进制下的第 bit 位的贡献是有规律的,是一个长度为 2bit+1 的循环节,其中前半部分是 0 ,后半部分是 1。

那么一种较为朴素的想法是从当前节点 pos 向上跳,将其 k 级祖先的每个点的每个二进制位都按照上表对应1的异或一下,但是这样是 O(n2logV) 的。或许你能想到树链剖分一下,但是那样也只是O(nlog2n×logV)

假设现在我们只考虑 bit 位上的贡献:
我们考虑利用一下循环节这一特性,我们可以打一个差分,来维护那些点需要异或上1,然后我们就发现,对于一个点 pos 他能贡献到的所有节点的深度对 2bit 取模之后是同余的。所以我们可以维护一个桶 w[j][dep],用来表示在第 j 位上,深度对 2bit 取模后为 dep 的点的答案应该异或上 w[j][dep]

那么如何保证子树内节点只对祖先贡献呢?很简单,我们对 w 再差分一下就好了,记录一下进入每个节点时桶的状态 ans。退出这个节点时再拿退出时的桶 wans 异或取到真正的答案。

Code:

#include<bits/stdc++.h>
#define int long long
const int N=6e5+5;
const int lg=20;
using namespace std;
int bit[lg+5],full_bit[lg+5];
int w[lg+5][N],val[N];
vector<int> E[N];
int n,sum;
void init()
{
for(int i=0;i<=lg;i++)bit[i]=(1ll<<i);
for(int i=0;i<=lg;i++)full_bit[i]=bit[i]-1;
}
int dfs(int x,int dep)
{
int ans=val[x];
for(int j=0;j<=lg;j++)w[j][(dep+val[x])&(full_bit[j])]^=bit[j];//&full_bit :对2^j 取模
for(int j=0;j<=lg;j++)ans^=w[j][dep&(full_bit[j])];
for(auto y : E[x])ans^=dfs(y,dep+1);
for(int j=0;j<=lg;j++)ans^=w[j][dep&(full_bit[j])];
sum+=ans;
return ans;
}
void work()
{
cin>>n;
init();
for(int i=1;i<=n;i++)scanf("%lld",&val[i]);
for(int u=2,v;u<=n;u++)scanf("%lld",&v),E[v].emplace_back(u);
dfs(1,0);
cout<<sum;
}
#undef int
int main()
{
//freopen("P6623.in","r",stdin);freopen("P6623.out","w",stdout);
work();
return 0;
}
posted @   liuboom  阅读(3)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· PowerShell开发游戏 · 打蜜蜂
· 在鹅厂做java开发是什么体验
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
点击右上角即可分享
微信分享提示