浙农大第十九届程序设计竞赛 J-Tree & 树上启发式合并的理解

Tree

https://ac.nowcoder.com/acm/contest/7872/J

Tree

前言

树上启发式合并好啊,可惜还不太会啊图片说明

分析

1.凡事始于朴素:根据题目,我得在每一个子树内部去寻找答案。
图片说明
假设是这样的一棵树。首先在3节点的子树中去找,首先遍历4节点,
图片说明
统计一下,这时的lca是3,记录一个k并求出图片说明 表示另一个数的出现次数,同时图片说明 。然后去到5节点,
图片说明
同样的,首先找到满足图片说明 的数的个数,同时将图片说明
然后进入10号节点....
图片说明
这个时候我们发现已经统计完了3节点的子树,向上走一步同时vis数组清零,到达2号,根据统计3节点子树的方法一样,先把3节点所有子树加入贡献(注意,是把vis清零后再重新跑一遍3节点的子树)
图片说明
然后再进入6节点,统计答案....

2.会发现,有许多不必要的重复操作,我为什么要把3节点子树的vis清零呢?我一定要把所有的都清零吗?于是树上启发式合并就来了。名字听着挺nb的,其实就是最大减少重复操作。就比如,在这棵树中,我如果要减少重复操作,明显就得最小化进入节点较多的子树的次数。也就是说,尽可能多的保留重儿子的信息(不清零),在统计时,只需要搜索轻儿子。
先给出代码

inline void dsu(int u,int v,bool w)
{
    for (int i=h[u];~i;i=nex[i])
    {
        int j=ver[i];
        if(j==v||j==son[u]) continue;
        dsu(j,u,0);
    }
    if(son[u]) dsu(son[u],u,1);

    for (int i=h[u];~i;i=nex[i])
    {
        int j=ver[i];
        if(j==v||j==son[u]) continue;

        cal(j,u,u),upd(j,u,1);
    }

    k[val[u]]++;
    if(!w) upd(u,v,-1);
}

然后看图模拟一遍(以1节点为lca统计答案):首先,重儿子(节点数最多的那个)为2,先跑入7,9节点统计完这两个子树对答案产生的贡献之后,再加入重儿子
图片说明
会发现,此时2节点的子树内部信息不会被清零,
图片说明
然后开始与轻儿子统计对答案的贡献,避免了重新进入2号节点统计每一个值的出现个数的问题。

代码

/*树上启发式合并*/
#include<bits/stdc++.h>

#define R register
#define ll long long
#define inf INT_MAX

using namespace std;

const int N=1e5+10;

int n,tot;ll ans;
int h[N],nex[N<<1],ver[N<<1];
int son[N],val[N],siz[N];

map<int,int>k;

inline void add(int x,int y)
{
    nex[tot]=h[x];
    ver[tot]=y;
    h[x]=tot++;
}

inline void dfs(int u,int v)
{
    siz[u]=1;
    for (int i=h[u];~i;i=nex[i])
    {
        int j=ver[i];
        if(j==v) continue;

        dfs(j,u);

        siz[u]+=siz[j];
        if(siz[son[u]]<siz[j]) son[u]=j;
    }
}

inline void cal(int u,int v,int lca)
{
    ans+=(ll)k[2*val[lca]-val[u]];
    for (int i=h[u];~i;i=nex[i])
        if(ver[i]!=v) cal(ver[i],u,lca);
}

inline void upd(int u,int v,int va)
{
    k[val[u]]+=va;
    for (int i=h[u];~i;i=nex[i])
        if(ver[i]!=v)
            upd(ver[i],u,va);
}

inline void dsu(int u,int v,bool w)
{
    for (int i=h[u];~i;i=nex[i])
    {
        int j=ver[i];
        if(j==v||j==son[u]) continue;
        dsu(j,u,0);
    }
    if(son[u]) dsu(son[u],u,1);

    for (int i=h[u];~i;i=nex[i])
    {
        int j=ver[i];
        if(j==v||j==son[u]) continue;

        cal(j,u,u),upd(j,u,1);
    }

    k[val[u]]++;
    if(!w) upd(u,v,-1);
}

int main()
{
    memset(h,-1,sizeof(h));
    scanf("%d",&n);
    for (int i=1;i<=n;i++) scanf("%d",&val[i]);
    for (int i=1;i<n;i++)
    {
        int x,y;
        scanf("%d%d",&x,&y);
        add(x,y),add(y,x);
    }

    dfs(1,0);
    dsu(1,1,0);

    printf("%lld\n",ans*2ll);

    return 0;
}

后话

篇幅极短,且用词不规范,不知是否会误导其他人(应该也没多少人看)

比赛题解 文章被收录于专栏

牛客IOI周赛,团队赛,练习赛,挑战赛,各种模拟赛的部分题解

全部评论

相关推荐

最近又搬回宿舍了,在工位坐不住,写一写秋招起伏不断的心态变化,也算对自己心态的一些思考表演式学习从开始为实习准备的时候就特别焦虑,楼主一开始选择的是cpp后端,但是24届这个方向已经炸了,同时自己又因为本科非92且非科班,所以感到机会更加迷茫。在某天晚上用java写出hello&nbsp;world并失眠一整晚后选择老本行干嵌入式。理想是美好的,现实情况是每天忙但又没有实质性进展,总是在配环境,调工具,顺带还要推科研。而这时候才发现自己一直在表演式学习,徘徊在设想如何展开工作的循环里,导致没有实质性进展。现在看来当时如果把精力专注在动手写而不是两只手端着看教程,基本功或许不会那么差。实习的焦虑5月,楼主...
耶比:哲学上有一个问题,玛丽的房间:玛丽知道眼睛识别色彩的原理知道各种颜色,但是她生活在黑白的房间里,直到有一天玛丽的房门打开了她亲眼看到了颜色,才知道什么是色彩。我现在最大可能的减少对非工作事情的思考,如果有一件事困扰了我, 能解决的我就直接做(去哪里或者和谁吵架等等……),解决不了的我就不想了,每一天都是最年轻的一天,珍惜今天吧
投递比亚迪等公司10个岗位 > 秋招被确诊为…… 牛客创作赏金赛
点赞 评论 收藏
分享
点赞 评论 收藏
分享
11-14 16:13
已编辑
重庆科技大学 测试工程师
Amazarashi66:不进帖子我都知道🐮❤️网什么含金量
点赞 评论 收藏
分享
评论
5
收藏
分享
正在热议
# 25届秋招总结 #
442405次浏览 4511人参与
# 春招别灰心,我们一人来一句鼓励 #
41942次浏览 531人参与
# 阿里云管培生offer #
120248次浏览 2220人参与
# 地方国企笔面经互助 #
7962次浏览 18人参与
# 同bg的你秋招战况如何? #
76670次浏览 561人参与
# 虾皮求职进展汇总 #
115613次浏览 886人参与
# 北方华创开奖 #
107433次浏览 599人参与
# 实习,投递多份简历没人回复怎么办 #
2454658次浏览 34857人参与
# 实习必须要去大厂吗? #
55771次浏览 961人参与
# 提前批简历挂麻了怎么办 #
149901次浏览 1977人参与
# 投递实习岗位前的准备 #
1195935次浏览 18548人参与
# 你投递的公司有几家约面了? #
33206次浏览 188人参与
# 双非本科求职如何逆袭 #
662208次浏览 7394人参与
# 如果公司给你放一天假,你会怎么度过? #
4753次浏览 55人参与
# 机械人春招想让哪家公司来捞你? #
157628次浏览 2267人参与
# 如果你有一天可以担任公司的CEO,你会做哪三件事? #
11561次浏览 287人参与
# 发工资后,你做的第一件事是什么 #
12704次浏览 62人参与
# 工作中,努力重要还是选择重要? #
35804次浏览 384人参与
# 参加完秋招的机械人,还参加春招吗? #
20126次浏览 240人参与
# 我的上岸简历长这样 #
452016次浏览 8088人参与
# 实习想申请秋招offer,能不能argue薪资 #
39299次浏览 314人参与
# 非技术岗是怎么找实习的 #
155868次浏览 2120人参与
牛客网
牛客企业服务