zoukankan      html  css  js  c++  java
  • 联合省选2020 树

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

    (x) 号结点的子树内(包含 (x) 自身)的所有结点编号为 (c_1, c_2, dots, c_k),定义 (x) 的价值为:

    [val(x) = (v_{c_1} + d(c_1, x)) oplus (v_{c_2} + d(c_2, x)) oplus cdots oplus (v_{c_k} + d(c_k, x)) ]

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

    请你求出 (sum_{i=1}^n val(i)) 的结果。

    (100\%) 的数据:(1le n, v_i le 525010, 1le p_ile n)

    Trie

    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(nlog 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
    ",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
    ",accumulate(f+1,f+n+1,0LL));
    	return 0;
    }
    
  • 相关阅读:
    Windows XP下Qemu模拟器上OpenSolaris的安置
    图解SMC下Solaris用户图形经管(下)
    Solaris 10的功能
    在Solaris 下用DVD光盘保存数据(1)
    Solaris10下载、安设和设置装备摆设(2)
    Solaris 10密码忘记打点法子
    对Unix任事器进行性能监测(上)
    Solaris效力打点东西 SMF快速入门指南(3)
    Solaris 10主动安顿DVD运用步骤
    Solaris效劳经管器材 SMF疾速入门指南(2)
  • 原文地址:https://www.cnblogs.com/autoint/p/13235181.html
Copyright © 2011-2022 走看看