DSU on tree

这次的ccpc   是我演了  我看出了这个不会写  是我的问题

重新开始认真学一遍dsu on tree,之前只是了解了思想就以为自己能摸,结果.....千错万错都是我的错,我演了  dbq

板子题链接

对于每个节点重儿子子树只统计一遍,轻儿子暴力统计+撤销影响(这一操作是为了重复利用数组,不炸空间),每个轻儿子最多被暴力log次

#include<bits/stdc++.h>
using namespace std;
const int N=2e5+7;
typedef long long ll;
const ll inf=1e18;
const int mod=998244353;
vector<int>son[N];
int siz[N];
int er[N];
int a[N];
int cnt[N];
ll Son,sum=0;
ll ans[N];
int ma;
void dfs(int x,int fa)
{
    siz[x]=1;
    for(int i=0;i<son[x].size();i++)
    {
        int d=son[x][i];
        if(d==fa) continue;
        dfs(d,x);
        if(siz[d]>siz[er[x]]) er[x]=d;
        siz[x]+=siz[d];
    }
}
void add(int x,int fa,int val)
{

    cnt[a[x]]+=val;
    if(cnt[a[x]]>ma) ma=cnt[a[x]],sum=a[x];
    else if(cnt[a[x]]==ma) sum+=a[x];
    for(int i=0;i<son[x].size();i++)
    {
        int d=son[x][i];
        if(d==fa||d==Son) continue;
        add(d,x,val);
    }
}
void dfs2(int x,int fa,int op)
{
    //cout<<x<<' '<<'?'<<endl;
    for(int i=0;i<son[x].size();i++)
    {
        int d=son[x][i];
        if(d==fa||d==er[x]) continue;
        dfs2(d,x,0);
    }
    if(er[x])dfs2(er[x],x,1),Son=er[x];
    add(x,fa,1);Son=0;
    ans[x]=sum;
    //cout<<'!'<<x<<' '<<ans[x]<<' '<<ma<<endl;
    if(!op) add(x,fa,-1),sum=0,ma=0;//撤销轻儿子影响
}
signed main()
{
    int n;
    cin>>n;
    for(int i=1;i<=n;i++)
        cin>>a[i];
    for(int i=1;i<n;i++)
    {
        int a1,a2;
        cin>>a1>>a2;
        son[a1].push_back(a2);
        son[a2].push_back(a1);
    }
    //son[1].push_back(0);
    dfs(1,0);
    //for(int i=1;i<=n;i++) cout<<er[i]<<' ';cout<<endl;
    dfs2(1,0,0);

    for(int i=1;i<=n;i++)
        cout<<ans[i]<<' ';
    cout<<endl;
}

长春的题明天补了再放代码

已补

题目大意给你一棵树,每个节点都有个权值,如果a[i]^a[j]=a[lca(i,j)]   ans+=(i^j)

板子题,和上面那题差不多就是要注意枚举最近公共祖先节点时,需要先把轻儿子子树的贡献算了,再把轻儿子子树加进数组中

AC代码

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define int ll
const int N=2e5+7;
const ll inf=1e18;
const int mod=998244353;
vector<int>son[N];
int siz[N];
int er[N];
int a[N];
int cnt[N*6][20];
int num[N*6];
ll Son,sum=0;
ll ans;
int ma;int n;
void dfs(int x,int fa)
{
    siz[x]=1;
    for(int i=0;i<son[x].size();i++)
    {
        int d=son[x][i];
        if(d==fa) continue;
        dfs(d,x);
        if(siz[d]>siz[er[x]]) er[x]=d;
        siz[x]+=siz[d];
    }
}
void gai(int x,int fa,int val)
{

    for(int i=0;i<20;i++)
    {
        if(x&(1<<i))
        cnt[a[x]][i]+=val;
    }
    num[a[x]]+=val;
    for(int i=0;i<son[x].size();i++)
    {
        int d=son[x][i];
        if(d==fa) continue;
        gai(d,x,val);
    }

}

void add(int x,int fa,int zu)
{
    int d=a[x]^a[zu];
        //cout<<x<<' '<<d<<' '<<zu<<'!'<<' '<<num[d]<<endl;
    for(int i=0;i<20;i++)
    {
        if(x&(1<<i))
            ans+=(num[d]-cnt[d][i])*(1<<i);

        else
            ans+=cnt[d][i]*(1<<i);
    }
    for(int i=0;i<son[x].size();i++)
    {
        int d=son[x][i];
        if(d==fa||d==Son) continue;
        add(d,x,zu);
    }

}

void dfs2(int x,int fa,int op)
{
    //cout<<x<<' '<<'?'<<endl;
    for(int i=0;i<son[x].size();i++)
    {
        int d=son[x][i];
        if(d==fa||d==er[x]) continue;
        dfs2(d,x,0);
    }
    if(er[x]) dfs2(er[x],x,1),Son=er[x];
   /* for(int i=1;i<=n;i++)
    {
        for(int j=0;j<4;j++)
             cout<<cnt[i][j]<<' ';
        cout<<endl;
    }*/

     for(int i=0;i<son[x].size();i++)
    {
        int d=son[x][i];
        if(d==fa||d==er[x]) continue;
        add(d,x,x);
        gai(d,x,1);
    }
    for(int i=0;i<20;i++)
    {
        if(x&(1<<i))
        cnt[a[x]][i]++;
    }
    num[a[x]]++;
    //cout<<'?'<<x<<' '<<ans<<endl;
   /*for(int i=1;i<=n;i++)
    {
        for(int j=0;j<4;j++)
             cout<<cnt[i][j]<<' ';
        cout<<endl;
    }*/
    //cout<<"SSSSSSSS"<<endl;
    Son=0;
    if(!op)
    {
    for(int i=0;i<20;i++)
    {
        if(x&(1<<i))
        cnt[a[x]][i]--;
    }
    num[a[x]]--;
    for(int i=0;i<son[x].size();i++)
    {
        int d=son[x][i];
        if(d==fa) continue;
        gai(d,x,-1);
    }
    }
}
signed main()
{

    cin>>n;
    for(int i=1;i<=n;i++)
        cin>>a[i];
    for(int i=1;i<n;i++)
    {
        int a1,a2;
        cin>>a1>>a2;
        son[a1].push_back(a2);
        son[a2].push_back(a1);
    }
    //son[1].push_back(0);
    dfs(1,0);
    //for(int i=1;i<=n;i++) cout<<er[i]<<' ';cout<<endl;
    dfs2(1,0,0);
    cout<<ans<<endl;
}
/*
7
2 1 7 6 3 2 3
1 2
1 2
1 4
1 5
2 6
3 7
*/

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值