zoukankan      html  css  js  c++  java
  • Luogu P6623 [省选联考 2020 A 卷] 树|Trie

    Luogu P6623 [省选联考 2020 A 卷] 树|01Trie

    题目链接

    题目大意:

    [1leq n,v_i leq 525010,1leq p_ileq n ]

    思路:

    这题有写树上差分的,桶+Dsu on tree的,这里来一种01trie的方法。

    考虑使用dfs,在每个点维护一个trie,对于每个节点,先与子节点的trie合并,然后按位统计该位(0/1)个数,并在向上更新答案时进行(+1)的操作,得出答案。

    二进制中的加(1),就是从末位开始,若该位为(1),则变(0),同时往下一为加(1),直到该位为(0),则变(1),因此在树中不断交换(0)子树和(1)子树,并向(0)子树递归即可。显而易见的,建树要从最低位开始建。

    01trie中的合并与线段树合并相差不大,稍作修改即可。

    上代码:

    #include<bits/stdc++.h>
    using namespace std;
    int w[530000][22][2],g,tmp,rot[530000];
    //在实现中,用w数组存每个节点每位的0/1个数
    int cc,to[530000],net[530000],fr[530000],v[530000],n,fa;
    long long ans;
    struct trie
    {
    	int f0,f1,s;
    }t[30052210];//需要空间较大,务必注意
    void addedge(int u,int v)
    {
    	cc++;
    	to[cc]=v;net[cc]=fr[u];fr[u]=cc;
    }
    void add(int x,int y,int v)
    {
    	t[x].s++;
    	if (y==21) return ;
    	if (v&1)
    	{
    		if (!t[x].f1) g++;t[x].f1=g;
    		add(t[x].f1,y+1,v>>1);w[tmp][y+1][1]++;
    	}
    	else
    	{
    		if (!t[x].f0) g++;t[x].f0=g;
    		add(t[x].f0,y+1,v>>1);w[tmp][y+1][0]++;
    	}
    }
    void hebing(int x,int y)
    {
    	t[x].s+=t[y].s;
    	if ((!x)||(!y)) return;
    	if (t[y].f0&&!t[x].f0)
    		t[x].f0=t[y].f0;
    	else hebing(t[x].f0,t[y].f0); 
    	if (t[y].f1&&!t[x].f1)
    	    t[x].f1=t[y].f1;
    	else hebing(t[x].f1,t[y].f1);
    } //01trie合并
    void plusone(int x,int y)
    {
    	if (!x) return ;
    	w[tmp][y+1][0]-=t[t[x].f0].s;
    	w[tmp][y+1][1]-=t[t[x].f1].s;
    	swap(t[x].f0,t[x].f1);
    	w[tmp][y+1][0]+=t[t[x].f0].s;
    	w[tmp][y+1][1]+=t[t[x].f1].s;	
    	plusone(t[x].f0,y+1);
    }//加一
    void dfs(int x)
    {	
    	int s=0;
    	rot[x]=++g;
    	tmp=x;add(rot[x],0,v[x]);
    	for (int i=fr[x];i;i=net[i])
    	{
    		dfs(to[i]);
    		hebing(rot[x],rot[to[i]]);
    		for (int j=1;j<=21;j++)
    		{		
    			w[x][j][0]+=w[to[i]][j][0];
    			w[x][j][1]+=w[to[i]][j][1];
    		}
    	}
    	for (int i=1;i<=21;i++)
    	{
    		if (w[x][i][1]%2) s+=1<<(i-1);
    	}
    	ans+=s;
    	tmp=x;plusone(rot[x],0);
    }
    int main()
    {
    	scanf("%d",&n);
    	for (int i=1;i<=n;i++)
    	{
    		scanf("%d",&v[i]);
    	}
    	for (int i=2;i<=n;i++)
    	{
    		scanf("%d",&fa);
    		addedge(fa,i);
    	}
    	dfs(1);
    	cout<<ans<<endl;
    	return 0;
    }
    
  • 相关阅读:
    Hadoop学习笔记(1) ——菜鸟入门
    自己动手做个智能小车(8)[终]
    自己动手做个智能小车(7)
    自己动手做个智能小车(6)
    CSS动画
    smarty的缓冲
    smarty模板
    修改登录密码
    登录验证码
    phpcms
  • 原文地址:https://www.cnblogs.com/fmj123/p/13746968.html
Copyright © 2011-2022 走看看