BZOJ

LOJ

洛谷


\(Kelin\)写的挺清楚的...

要求如果\(a_{p_j}=p_k\),\(k\lt j\),可以理解为\(k\)要在\(j\)之前选。

那么对于给定的\(a_j=k\),我们可以连边\(k\to j\)建一张图。如果图有环,那么无解;否则这是一棵以\(0\)为根的树。

限制就变成了,选一个点前必须要选其父亲;如果第\(k\)个选点\(i\),\(i\)的贡献是\(k\cdot w_i\)。

然后怎么做呢...

假设当前最小的数是\(x\),那么如果\(fa[x]\)选过,现在一定选\(x\);否则如果有一次选了\(fa[x]\),下一次一定选\(x\)。

考虑到按顺序选点实际是构成一个序列,且上面的\(x\)一定和\(fa[x]\)在序列中挨在一起。所以考虑把\(x,fa[x]\)合并成一个序列,再考虑其它的。

之前是比点权,现在我们要比较序列与序列之间谁放在后面更优。

考虑两个序列\(a,b\),设\(a\)中有\(t_1\)个点,\(b\)中有\(t_2\)个点,假设现在已经选了\(k\)个点,那么\(ab,ba\)的贡献分别为$$W_{ab}=\sum_{i=1}{t_1}(k+i)w_{a_i}+\sum_{i=1}{t_2}(k+i+t_1)w_{b_i}\W_{ba}=\sum_{i=1}{t_2}(k+i)w_{b_i}+\sum_{i=1}{t_1}(k+i+t_2)w_{a_i}\W_{ab}-W_{ba}=t_1\sum w_{b_i}-t_2\sum w_{a_i}$$

那么\(W_{ab}>W_{ba}\Rightarrow \frac{\sum w_{b_i}}{t_2}>\frac{\sum w_{a_i}}{t_1}\),即平均数更小的放到前面更优。

所以我们就可以拿堆维护了,每次取出最小的,把它与父节点所在序列合并。这里可以用带修改堆修改父节点的状态,也可以打个标记删掉父节点的状态(其实判一下\(sz\)是否等于当前状态下的\(sz\)就可以了)。

答案就在一个序列被放到后面的时候统计就可以了。

另外堆也可以用\(STL\)里的\(heap\)。只需要#include <algorithm>

常数应该是比priority_queue小一些的?可能是我写的丑...


priority_queue

//30268kb	2620ms
#include <queue>
#include <cstdio>
#include <cctype>
#include <cstdlib>
#include <algorithm>
//#define gc() getchar()
#define MAXIN 500000
#define gc() (SS==TT&&(TT=(SS=IN)+fread(IN,1,MAXIN,stdin),SS==TT)?EOF:*SS++)
typedef long long LL;
const int N=5e5+5; int Cnt,fa[N],Enum,H[N],nxt[N],to[N],F[N],sz[N];
LL w[N];
char IN[MAXIN],*SS=IN,*TT=IN;
struct Node
{
int x,sz; LL val;
bool operator <(const Node &x)const
{
return val*x.sz>x.val*sz;
}
}; inline int read()
{
int now=0;register char c=gc();
for(;!isdigit(c);c=gc());
for(;isdigit(c);now=now*10+c-48,c=gc());
return now;
}
inline void AE(int u,int v)
{
to[++Enum]=v, nxt[Enum]=H[u], H[u]=Enum;
}
void DFS(int x)
{
static bool vis[N];
++Cnt, vis[x]=1;
for(int i=H[x]; i; i=nxt[i])
if(!vis[to[i]]) DFS(to[i]);
else {puts("-1"); exit(0);}
}
int Find(int x)
{
return x==F[x]?x:F[x]=Find(F[x]);
} int main()
{
// freopen("perm.in","r",stdin);
// freopen("perm.out","w",stdout); const int n=read();
for(int i=1; i<=n; ++i) AE(fa[i]=read(),i);
DFS(0);
if(Cnt<=n) return puts("-1"),0;
std::priority_queue<Node> q;
for(int i=0; i<=n; ++i) F[i]=i, sz[i]=1;//from 0
for(int i=1; i<=n; ++i) q.push((Node){i,1,w[i]=read()});
LL ans=0;
while(!q.empty())
{
Node tmp=q.top(); q.pop();
int x=Find(tmp.x);
if(tmp.sz!=sz[x]) continue;
int r=Find(fa[x]);
F[x]=r, ans+=tmp.val*sz[r], sz[r]+=sz[x], w[r]+=w[x];
if(r) q.push((Node){r,sz[r],w[r]});
}
printf("%lld\n",ans); return 0;
}

heap

//25792kb	2716ms
#include <cstdio>
#include <cctype>
#include <cstdlib>
#include <algorithm>
//#define gc() getchar()
#define MAXIN 500000
#define gc() (SS==TT&&(TT=(SS=IN)+fread(IN,1,MAXIN,stdin),SS==TT)?EOF:*SS++)
typedef long long LL;
const int N=5e5+5; int Cnt,fa[N],Enum,H[N],nxt[N],to[N],F[N],sz[N];
LL w[N];
char IN[MAXIN],*SS=IN,*TT=IN;
struct Node
{
int x,sz; LL val;
bool operator <(const Node &x)const
{
return val*x.sz>x.val*sz;
}
}q[N]; inline int read()
{
int now=0;register char c=gc();
for(;!isdigit(c);c=gc());
for(;isdigit(c);now=now*10+c-48,c=gc());
return now;
}
inline void AE(int u,int v)
{
to[++Enum]=v, nxt[Enum]=H[u], H[u]=Enum;
}
void DFS(int x)
{
static bool vis[N];
++Cnt, vis[x]=1;
for(int i=H[x]; i; i=nxt[i])
if(!vis[to[i]]) DFS(to[i]);
else {puts("-1"); exit(0);}
}
int Find(int x)
{
return x==F[x]?x:F[x]=Find(F[x]);
} int main()
{
// freopen("perm.in","r",stdin);
// freopen("perm.out","w",stdout); const int n=read();
for(int i=1; i<=n; ++i) AE(fa[i]=read(),i);
DFS(0);
if(Cnt<=n) return puts("-1"),0;
for(int i=0; i<=n; ++i) F[i]=i, sz[i]=1;//from 0
for(int i=1; i<=n; ++i) q[i]=(Node){i,1,w[i]=read()};
LL ans=0; int cnt=n;
std::make_heap(q+1,q+1+cnt);
while(cnt)
{
Node tmp=q[1]; std::pop_heap(q+1,q+1+cnt), --cnt;
int x=Find(tmp.x);
if(tmp.sz!=sz[x]) continue;
int r=Find(fa[x]);
F[x]=r, ans+=tmp.val*sz[r], sz[r]+=sz[x], w[r]+=w[x];
if(r) q[++cnt]=(Node){r,sz[r],w[r]}, std::push_heap(q+1,q+1+cnt);
}
printf("%lld\n",ans); return 0;
}

BZOJ.5289.[AHOI/HNOI2018]排列(贪心 heap)的更多相关文章

  1. BZOJ.5288.[AHOI/HNOI2018]游戏(思路 拓扑)

    BZOJ LOJ 洛谷 考虑如何预处理每个点能到的区间\([l,r]\). 对于\(i,i+1\)的一扇门,如果钥匙在\(i\)的右边,连边\(i\to i+1\),表示从\(i\)出发到不了\(i+ ...

  2. BZOJ.5290.[AHOI/HNOI2018]道路(树形DP)

    BZOJ LOJ 洛谷 老年退役选手,都写不出普及提高DP= = 在儿子那统计贡献,不是在父亲那统计啊!!!(这样的话不写这个提高DP写记忆化都能过= =) 然后就令\(f[x][a][b]\)表示在 ...

  3. BZOJ.5287.[AHOI HNOI2018]毒瘤(虚树 树形DP)

    BZOJ LOJ 洛谷 设\(f[i][0/1]\)表示到第\(i\)个点,不选/选这个点的方案数.对于一棵树,有:\[f[x][0]=\prod_{v\in son[x]}(f[v][0]+f[v] ...

  4. BZOJ.5285.[AHOI/HNOI2018]寻宝游戏(思路 按位计算 基数排序..)

    BZOJ LOJ 洛谷 话说vae去年的专辑就叫寻宝游戏诶 只有我去搜Mystery Hunt和infinite corridor了吗... 同样按位考虑,假设\(m=1\). 我们要在一堆\(01\ ...

  5. BZOJ.5286.[AHOI/HNOI2018]转盘(线段树)

    BZOJ LOJ 洛谷 如果从\(1\)开始,把每个时间\(t_i\)减去\(i\),答案取决于\(\max\{t_i-i\}\).记取得最大值的位置是\(p\),答案是\(t_p+1+n-1-p=\ ...

  6. 5289: [Hnoi2018]排列

    5289: [Hnoi2018]排列 链接 分析: 首先将题意转化一下:每个点向a[i]连一条边,构成了一个以0为根节点的树,要求选一个拓扑序,点x是拓扑序中的第i个,那么价值是i*w[x].让价值最 ...

  7. 【BZOJ5289】[HNOI2018]排列(贪心)

    [BZOJ5289][HNOI2018]排列(贪心) 题面 BZOJ 洛谷 题解 这个限制看起来不知道在干什么,其实就是找到所有排列\(p\)中,\(p_k=x\),那么\(k<j\),其中\( ...

  8. loj #2509. 「AHOI / HNOI2018」排列

    #2509. 「AHOI / HNOI2018」排列   题目描述 给定 nnn 个整数 a1,a2,…,an(0≤ai≤n),以及 nnn 个整数 w1,w2,…,wn.称 a1,a2,…,an 的 ...

  9. Loj #2495. 「AHOI / HNOI2018」转盘

    Loj #2495. 「AHOI / HNOI2018」转盘 题目描述 一次小 G 和小 H 原本准备去聚餐,但由于太麻烦了于是题面简化如下: 一个转盘上有摆成一圈的 \(n\) 个物品(编号 \(1 ...

随机推荐

  1. 小学生都看得懂的C语言入门(1): 基础/判别/循环

    c基础入门, 小学生也可以都看得懂!!!! 安装一个编译器, 这方面我不太懂, 安装了DEV-C++  ,体积不大,30M左右吧, 感觉挺好用,初学者够了. 介绍下DEV 的快键键: 恢复 Ctrl+ ...

  2. poj2441状态压缩dp基础

    /* 给定n头牛,m个谷仓,每头牛只能在一些特定的谷仓,一个谷仓只能有一头牛 问可行的安排方式 dp[i][j]表示前i头牛组成状态j的方案数,状态0表示无牛,1表示有牛 使用滚动数组即可 枚举到第i ...

  3. 如何在地址栏(title标签里)和收藏夹里 加上网站的标志ICO、LOGO图片

    第一步:首先你必须要制作一个看起来既清楚又容易辨识的.ico格式的小图片. 我们将图标的大小定义为16x16 像素.此外在制作图形文件的时候,你可能需要把色盘设定成只使用标准的 16 色 Window ...

  4. 常见的爬虫分析库(3)-Python正则表达式与re模块

    在线正则表达式测试 http://tool.oschina.net/regex/ 常见匹配模式 模式 描述 \w 匹配字母数字及下划线 \W 匹配非字母数字下划线 \s 匹配任意空白字符,等价于 [\ ...

  5. IDEA快捷键之for循环

    intelliJ生成for循环代码. 迭代器for循环 iter Iterate iterable | Array in J2SDK 5 syntax itar Iterate elements of ...

  6. 如何设置Navicat的显示字体与字体大小?

    方法/步骤     打开Navicat   点击[工具]菜单,再选择[选项]   在[选项]界面,点击[外观]下的[字体]   设置网格字体和大小   设置编辑器字体和大小   设置命令列界面字体和大 ...

  7. Top 查看某些或者某个进程(top -p pid)

    https://blog.csdn.net/zhangfn2011/article/details/7488746?utm_source=blogxgwz5

  8. js中类定义函数时用prototype与不用的区别

    转载自:https://blog.csdn.net/yexudengzhidao/article/details/72866047 先看例子 function ListCommon2(first,se ...

  9. [转]PL/SQL Developer 导入导出csv文件

    PL/SQL Developer 可以导入或者导出CSV文件. 导入CSV文件步骤: 1.选择tools->text importer.... 2.选择第二个Data to oracle选项卡, ...

  10. Codeforces 980F Cactus to Tree 仙人掌 Tarjan 树形dp 单调队列

    原文链接https://www.cnblogs.com/zhouzhendong/p/CF980F.html 题目传送门 - CF980F 题意 给定一个 $n$ 个节点 $m$ 条长为 $1$ 的边 ...