标签:span mat 维护 article sdn else net 表示 int
给定一棵 \(n\) 个结点的有根树 \(T\),结点从 \(1\) 开始编号,根结点为 \(1\) 号结点,每个结点有一个正整数权值 \(v_i\)。
设 \(x\) 号结点的子树内(包含 \(x\) 自身)的所有结点编号为 \(c_1, c_2, \dots, c_k\),定义 \(x\) 的价值为:
其中 \(d(x, y)\) 表示树上 \(x\) 号结点与 \(y\) 号结点间唯一简单路径所包含的边数,\(d(x, x) = 0\)。\(\oplus\) 表示异或运算。
请你求出 \(\sum_{i=1}^n val(i)\) 的结果。
\(100\%\) 的数据:\(1\le n, v_i \le 525010, 1\le p_i\le n\)。
https://blog.csdn.net/qq_39854734/article/details/106946271
https://blog.csdn.net/qq_33229466/article/details/106927385
考虑用 01-Trie 来维护所有\(v(c_j)+d(c_j,x)\),并启发式合并。
01-Trie 需要支持:插入一个数;求全局异或和;全局加一。
前两个操作容易维护(全局异或和需要每个节点记录其子树里所有数在一些位的异或和);
为了支持第三个操作,我们把数按从低位到高位放进 01-Trie,每次交换左右儿子,然后递归处理左(交换前是右)儿子,然后更新自己这个节点维护的异或和。
时间复杂度\(O(n\log n)\)。
CO int N=53e4;
int a[N],sum[N][21];
vector<int> to[N];
int root[N],tot;
int ch[N*25][2],siz[N*25];
void insert(int&x,int i,int v,int t){
if(!x) x=++tot;
++siz[x];
if(i==21) return;
if(v>>i&1) insert(ch[x][1],i+1,v,t),++sum[t][i];
else insert(ch[x][0],i+1,v,t);
}
void modify(int x,int i,int t){
if(!x or i==21) return;
sum[t][i]+=siz[ch[x][0]]-siz[ch[x][1]];
swap(ch[x][0],ch[x][1]);
modify(ch[x][0],i+1,t);
}
int merge(int x,int y){
if(!x or !y) return x+y;
siz[x]+=siz[y];
ch[x][0]=merge(ch[x][0],ch[y][0]);
ch[x][1]=merge(ch[x][1],ch[y][1]);
return x;
}
int64 ans;
void dfs(int x){
insert(root[x],0,a[x],x);
for(int y:to[x]){
dfs(y);
modify(root[y],0,y);
root[x]=merge(root[x],root[y]);
for(int i=0;i<=20;++i) sum[x][i]+=sum[y][i];
}
for(int i=0;i<=20;++i)if(sum[x][i]&1) ans+=1<<i;
}
int main(){
int n=read<int>();
for(int i=1;i<=n;++i) read(a[i]);
for(int i=2;i<=n;++i) to[read<int>()].push_back(i);
dfs(1);
printf("%lld\n",ans);
return 0;
}
https://www.luogu.com.cn/blog/dengyaotriangle/solution-p6623
看看就好。
CO int N=1<<21;
int a[N];
vector<int> to[N];
int w[21][N],f[N];
void dfs(int x,int d){
f[x]=a[x];
for(int i=0;i<=20;++i) f[x]^=w[i][d%(1<<i)];
for(int y:to[x]) dfs(y,d+1),f[x]^=f[y];
for(int i=0;i<=20;++i) f[x]^=w[i][d%(1<<i)];
for(int i=0;i<=20;++i) w[i][(d+a[x])%(1<<i)]^=1<<i;
}
int main(){
int n=read<int>();
for(int i=1;i<=n;++i) read(a[i]);
for(int i=2;i<=n;++i) to[read<int>()].push_back(i);
dfs(1,0);
printf("%lld\n",accumulate(f+1,f+n+1,0LL));
return 0;
}
标签:span mat 维护 article sdn else net 表示 int
原文地址:https://www.cnblogs.com/autoint/p/13235181.html