bzoj 5499: [2019省队联测]春节十二响【堆】

首先看两条链怎么合并,贪心可得是从大到小取max,多条链同理
所以dfs合并子树的大根堆即可,注意为了保证复杂度,合并的时候要合并到最长链上,证明见长链剖分

#include<iostream>
#include<cstdio>
#include<queue>
using namespace std;
const int N=200005;
int n,a[N],h[N],cnt,id[N],tot,p[N];
long long ans;
priority_queue<int>q[N];
struct qwe
{
    int ne,to;
}e[N<<1];
int read()
{
    int r=0,f=1;
    char p=getchar();
    while(p>'9'||p<'0')
    {
        if(p=='-')
            f=-1;
        p=getchar();
    }
    while(p>='0'&&p<='9')
    {
        r=r*10+p-48;
        p=getchar();
    }
    return r*f;
}
void add(int u,int v)
{
    cnt++;
    e[cnt].ne=h[u];
    e[cnt].to=v;
    h[u]=cnt;
}
void dfs(int u)
{//cerr<<u<<endl;
    id[u]=++tot;
    for(int i=h[u];i;i=e[i].ne)
    {
        dfs(e[i].to);
        if(q[id[e[i].to]].size()>q[id[u]].size())
            swap(id[e[i].to],id[u]);
        int len=q[id[e[i].to]].size();
        for(int j=1;j<=len;j++)
        {
            p[j]=max(q[id[e[i].to]].top(),q[id[u]].top());
            q[id[e[i].to]].pop();
            q[id[u]].pop();
        }
        for(int j=1;j<=len;j++)
            q[id[u]].push(p[j]);
    }
    q[id[u]].push(a[u]);
}
int main()
{
    n=read();
    for(int i=1;i<=n;i++)
        a[i]=read();
    for(int i=2;i<=n;i++)
    {
        int x=read();
        add(x,i);
    }
    dfs(1);
    while(!q[id[1]].empty())
        ans+=q[id[1]].top(),q[id[1]].pop();
    printf("%lld\n",ans);
    return 0;
}

原文地址:https://www.cnblogs.com/lokiii/p/10712388.html

时间: 2024-08-11 19:25:53

bzoj 5499: [2019省队联测]春节十二响【堆】的相关文章

bzoj 5496: [2019省队联测]字符串问题【SAM+拓扑】

有一个想法就是暴力建图,把每个A向有和他相连的B前缀的A,然后拓扑一下,这样的图是n^2的: 考虑优化建图,因为大部分数据结构都是处理后缀的,所以把串反过来,题目中要求的前缀B就变成了后缀B 建立SAM,发现在parent树中每个B能走到的A都在子树中,所以保留这个树结构,连边权为0的边: 然后在parent树上倍增找到每个AB串对应的点,因为SAM上每个对应不止一个串,所以找完之后把对应多个AB串的点拆成一条链 然后对于一对(x,y)的AB串关系,Ax对应的点向By对应的点连边权为A长度的边

bzoj 5498: [2019省队联测]皮配【dp】

是个神仙dp-- 参考:https://www.luogu.org/blog/xzz-233/solution-p5289 设f[i][j][k]是前i个有限制的城市,所有学校中选蓝色阵营有j人,有限制的学校中鸭派系有k人的方案数:g[i][j]是前i个没有限制的城市,蓝色阵营有j人的方案数:h[i][j]是前i个没有限制的学校,鸭派系有j人的方案数 f的转移枚举当前阵营 全dp出来之后,把gh前缀和处理,然后一段一段的和f合并加到ans上 #include<iostream> #includ

[十二省联考2019]春节十二响

好后悔考场没思考这道最良心的水题...t1花了我两个半点结果连20都拿不到 哭了 题目描述:略 思路:将一个点下面的几条链合并成一条 用长链剖分的话似乎可以简化操作 实在太水了所以没啥好说的... 1 #include<cstdio> 2 #include<queue> 3 using std::priority_queue; 4 typedef long long lint; 5 const int N=200011; 6 template<typename st>

P5290 [十二省联考2019]春节十二响

题目链接 题意分析 首先考虑链的话 就是将\(1\)部分的两条子链排序之后 贪心合并即可 那么考虑树的话 我们照样合并就行了 首先 排序的话 我们使用堆就可以了 然后 涉及到了两点问题 \(1.\)我们对于\(u\)以及\(v\)这两个维护好的堆合并的话 为了保证时间复杂度 我们需要使用启发式合并 \(2.\)我们由于启发式合并的话涉及到了交换两个堆的问题 听巨佬说 c++11的话 直接swap是\(O(1)\)的 否则的话 直接\(swap\)就是\(O(n)\) 所以我们考虑维护新的编号 然

[十二省联考2019]D2T2春节十二响

嘟嘟嘟 这题真没想到这么简单-- 首先有60分大礼:\(O(n ^ 2logn)\)贪心.(我也不知道为啥就是对的) 然后又送15分链:维护两个堆,每次去堆顶的最大值. 这时候得到75分已经很开心了,但其实离AC也就差一点点. 链的做法已经给了我们提示:合并两个堆.其实这就相当于二叉树.那多叉树呢?就合并多个堆呗!从子树向上递归的时候不断将子树启发式合并,复杂度就保证了. 代码真的很短 #include<cstdio> #include<iostream> #include<

[十二省联考]春节十二响

一个特殊的启发式合并 大概是sz(a)+sz(b)=sz(max(a,b)) 所以其实是一个log //Love and Freedom. #include<cstdio> #include<cmath> #include<algorithm> #include<cstring> #include<queue> #define ll long long #define inf 20021225 #define N 200100 using nam

[loj3052]春节十二响

首先可以发现对于两条链来说,显然是对两边都排好序,然后大的配大的,小的配小的(正确性比较显然),最后再加入根(根只能单独选)这个结果其实也可以理解为将所有max构成一条新的链,求出因此,对于每一个结点计算出答案,然后与别的点合并得到父亲,用启发式合并+set时间复杂度为两个log. 1 #include<bits/stdc++.h> 2 using namespace std; 3 #define N 200005 4 struct ji{ 5 int nex,to; 6 }edge[N];

“全栈2019”Java多线程第四十二章:获取线程与读写锁的保持数

难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java多线程第四十二章:获取线程与读写锁的保持数 下一章 "全栈2019"Java多线程第四十三章:查询是否有线程在等待读写锁 学习小组 加入同步学习小组,共同交流与进步. 方式一:关注头条号Gorhaf,私信"Java学习小组". 方式二:关注公众号Gorhaf,回复&quo

C语言入门(二十二)堆和链表

堆和链表  我们经常在题目中有要求,输入一个整数,然后以这个整数作为数组的元素个数,下面的程序代码是错误的. int n,array[n]; scanf(%d,&n); 在Turbo C中,不允许出现动态数组.那么如果必须需要这样时,就只能使用链表了. 一.堆 堆是一种动态存储结构,实际上就是数据段中的自由存储区,它是C语言中使用的一种名称,常常用于动态数据的存储分配.堆中存入一数据,总是以2字节的整数倍进行分配,地址向增加方向变动.堆可以不断进行分配直到没有堆空间为止,也可以随时进行释放.再分