首先确定将所有a[i]向i连边之后会形成一张图,图上每条有向边i->j表示i要在j之前选。

图上的每个拓扑序都对应一种方案(如果有环显然无解),经过一系列推导可以发现贪心策略与合并的块的大小和w之和有关,具体见https://kelin.blog.luogu.org/solution-p4437

贪心的时候每次要选w平均值最大的,这个可以用STL维护,具体使用哪种见下。

一:STL-priority_queue

最简单直接的做法,每次更新的时候直接加入即可,后面弹出的时候判一下这个点是否已经被更新即可。

BZOJ上AC,Luogu上开O2能A,不开会RE两个点。

 #include<cstdio>
#include<queue>
#include<algorithm>
#define rep(i,l,r) for (int i=(l); i<=(r); i++)
typedef long long ll;
using namespace std; const int N=;
int n,u,p,fa[N],tim,cnt,vis[N],f[N],sz[N],h[N],nxt[N<<],to[N<<];
ll ans,w[N];
struct D{ int u,sz; ll w; bool operator <(const D &b)const{ return w*b.sz>b.w*sz; } };
priority_queue<D>Q; void add(int u,int v){ to[++cnt]=v; nxt[cnt]=h[u]; h[u]=cnt; } void dfs(int u){
vis[u]=; tim++;
for (int i=h[u],v; i; i=nxt[i])
if (vis[v=to[i]]) { puts("-1"); exit(); } else dfs(v);
} int get(int x){ return (f[x]==x) ? x : f[x]=get(f[x]); } int main(){
freopen("bzoj5289.in","r",stdin);
freopen("bzoj5289.out","w",stdout);
scanf("%d",&n);
rep(i,,n) scanf("%d",&fa[i]),add(fa[i],i);
dfs(); if (tim<=n) { puts("-1"); return ; }
rep(i,,n) f[i]=i,sz[i]=;
rep(i,,n) scanf("%lld",&w[i]),Q.push((D){i,,w[i]});
while (!Q.empty()){
D s=Q.top(); Q.pop();
if (sz[u=get(s.u)]!=s.sz) continue;
f[u]=p=get(fa[u]); ans+=w[u]*sz[p];
w[p]+=w[u]; sz[p]+=sz[u];
if (p) Q.push((D){p,sz[p],w[p]});
}
printf("%lld\n",ans);
return ;
}

二:STL-set

我也不知道上面的方法为什么会RE,然后换成set就不存在这个问题了,取而代之的是超大常数。。

BZOJ上AC,Luogu上开O2能A,不开会TLE两个点。

 #include<cstdio>
#include<set>
#include<algorithm>
#define rep(i,l,r) for (int i=(l); i<=(r); i++)
typedef long long ll;
using namespace std; const int N=;
int n,u,p,fa[N],tim,cnt,vis[N],f[N],sz[N],h[N],nxt[N<<],to[N<<];
ll ans,w[N];
struct D{
int u,sz; ll w;
bool operator <(const D &b)const{ return (w*b.sz!=b.w*sz) ? w*b.sz<b.w*sz : ((u!=b.u)?u<b.u:(sz<b.sz)); }
};
multiset<D>Q; void add(int u,int v){ to[++cnt]=v; nxt[cnt]=h[u]; h[u]=cnt; } void dfs(int u){
vis[u]=; tim++;
for (int i=h[u],v; i; i=nxt[i])
if (vis[v=to[i]]) { puts("-1"); exit(); } else dfs(v);
} int get(int x){ return (f[x]==x) ? x : f[x]=get(f[x]); } int main(){
freopen("bzoj5289.in","r",stdin);
freopen("bzoj5289.out","w",stdout);
scanf("%d",&n);
rep(i,,n) scanf("%d",&fa[i]),add(fa[i],i);
dfs(); if (tim<=n) { puts("-1"); return ; }
rep(i,,n) f[i]=i,sz[i]=;
rep(i,,n) scanf("%lld",&w[i]),Q.insert((D){i,,w[i]});
while (!Q.empty()){
D s=*Q.begin(); Q.erase(s);
if (sz[u=get(s.u)]!=s.sz) continue;
f[u]=p=get(fa[u]); ans+=w[u]*sz[p];
w[p]+=w[u]; sz[p]+=sz[u];
if (p) Q.insert((D){p,sz[p],w[p]});
}
printf("%lld\n",ans);
return ;
}

三:__gnu_pbds::priority_queue

pb_ds库里的堆天生支持修改,但一般常数将是STL的接近三倍。

但是这题并没有体现,视平台不同而有所差异,BZOJ上和set同速,本机甚至比set和STL-priority_queue都快。

BZOJ上AC,Luogu上AC。

 #include<cstdio>
#include<ext/pb_ds/assoc_container.hpp>
#include<ext/pb_ds/priority_queue.hpp>
#include<algorithm>
#define rep(i,l,r) for (int i=(l); i<=(r); i++)
typedef long long ll;
using namespace std; const int N=;
int n,u,p,fa[N],tim,cnt,vis[N],f[N],sz[N],h[N],nxt[N<<],to[N<<];
ll ans,w[N];
struct D{ int u; ll w; };
struct Cmp{
bool operator()(const D &a,const D &b)const
{ return (a.w*sz[b.u]!=b.w*sz[a.u]) ? a.w*sz[b.u]>b.w*sz[a.u] : ((a.u!=b.u)?a.u>b.u:(sz[a.u]>sz[b.u])); }
};
__gnu_pbds::priority_queue<D,Cmp>Q;
__gnu_pbds::priority_queue<D,Cmp>::point_iterator its[N]; void add(int u,int v){ to[++cnt]=v; nxt[cnt]=h[u]; h[u]=cnt; } void dfs(int u){
vis[u]=; tim++;
for (int i=h[u],v; i; i=nxt[i])
if (vis[v=to[i]]) { puts("-1"); exit(); } else dfs(v);
} int get(int x){ return (f[x]==x) ? x : f[x]=get(f[x]); } int main(){
freopen("bzoj5289.in","r",stdin);
freopen("bzoj5289.out","w",stdout);
scanf("%d",&n);
rep(i,,n) scanf("%d",&fa[i]),add(fa[i],i);
dfs(); if (tim<=n) { puts("-1"); return ; }
rep(i,,n) f[i]=i,sz[i]=;
rep(i,,n) scanf("%lld",&w[i]),its[i]=Q.push((D){i,w[i]});
while (!Q.empty()){
int u=Q.top().u; Q.pop();
f[u]=p=get(fa[u]); ans+=w[u]*sz[p];
w[p]+=w[u]; sz[p]+=sz[u];
if (p) Q.modify(its[p],(D){p,w[p]});
}
printf("%lld\n",ans);
return ;
}

[BZOJ5289][HNOI2018]排列(拓扑排序+pb_ds)的更多相关文章

  1. [HNOI2018]游戏[拓扑排序]

    题意 题目链接 分析 先将没有锁的房间缩点,首先有一个 \(O(n^2)\) 的想法:从每个点出发,每次检查能否向两边扩张. 容易发现门和门之间如果有锁,必然只有一方能够开锁(只有一把钥匙),并且能够 ...

  2. BZOJ5289: [Hnoi2018]排列

    传送门 第一步转化,令 \(q[p[i]]=i\),那么题目变成: 有一些 \(q[a[i]]<q[i]\) 的限制,\(q\) 必须为排列,求 \(max(\sum_{i=1}^{n}w[i] ...

  3. [BZOJ5288][HNOI2018]游戏(拓扑排序)

    传送门:https://www.luogu.org/problemnew/show/P4436 20分的暴力加一个Random_shuffle就A了.我还能说什么.. 不过这个也不是毫无道理,复杂度应 ...

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

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

  5. 【BZOJ5288】[HNOI2018]游戏(拓扑排序)

    [BZOJ5288][HNOI2018]游戏(拓扑排序) 题面 BZOJ 洛谷 题解 去年省选的时候这题给我乱搞整过去整过去了,也是虐心了.... 所以当然是来讲正儿八经的正确做法啦. 很明显,我们需 ...

  6. 拓扑排序+不是字典序的优先级排列(POJ3687+HDU4857)

    一.前言 在过去的一周里结束了CCSP的比赛,其中有一道题卡了我9个小时,各种调错都没法完整的调处来这题,于是痛下决心开始补题,这个是计划的一部分.事实上,基于错误的理解我写了若干发拓扑排序+字典序的 ...

  7. uoj#278. 【UTR #2】题目排列顺序(拓扑排序)

    传送门 对于每一个位置\(i\)来说,上一个和它的\(f_i\)相同的点一定比它大,我们从上一个\(f_i\)和它相同的点向它连边.第一个\(f_i-1\)出现的位置一定比它小,把它向那个位置连边. ...

  8. 有向无环图的应用—AOV网 和 拓扑排序

    有向无环图:无环的有向图,简称 DAG (Directed Acycline Graph) 图. 一个有向图的生成树是一个有向树,一个非连通有向图的若干强连通分量生成若干有向树,这些有向数形成生成森林 ...

  9. ACM/ICPC 之 拓扑排序-反向(POJ3687)

    难点依旧是题意....需要反向构图+去重+看题 POJ3687-Labeling Balls 题意:1-N编号的球,输出满足给定约束的按原编号排列的重量序列,如果有多组答案,则输出编号最小的Ball重 ...

随机推荐

  1. ASP.NET Core ---异常处理

    一.局部异常处理: 在Action里面catch 二.全局异常处理: 1.默认的异常处理配置: 默认配置在StartUp文件的Configure中注册错误处理,显示开发者错误页面: public vo ...

  2. OpenCV_1.0安装包下载

    OpenCV_1.0安装包下载 点击下载

  3. python XlsxWriter创建Excel 表格

    文档(英文) https://xlsxwriter.readthedocs.io/index.html 常用模块说明(中文) https://blog.csdn.net/sinat_35930259/ ...

  4. PHP上传多文件

    知识点: 一.$_FILES数组 ①.$_FILES['filename']['name']上传文件原名 ②.$_FILES['filename']['tmp_name']上传成功后的缓存文件名 ③. ...

  5. xpath属性值的模糊匹配

    得至:http://bbs.csdn.net/topics/390857942  最后一楼 //div[contains(@class,'Number Skill')]

  6. POJ 3348 Cows | 凸包模板题

    题目: 给几个点,用绳子圈出最大的面积养牛,输出最大面积/50 题解: Graham凸包算法的模板题 下面给出做法 1.选出x坐标最小(相同情况y最小)的点作为极点(显然他一定在凸包上) 2.其他点进 ...

  7. BZOJ3143 [Hnoi2013]游走 【高斯消元】

    题目 一个无向连通图,顶点从1编号到N,边从1编号到M. 小Z在该图上进行随机游走,初始时小Z在1号顶点,每一步小Z以相等的概率随机选 择当前顶点的某条边,沿着这条边走到下一个顶点,获得等于这条边的编 ...

  8. 雅礼集训 Day1 T3 画作 解题报告

    画作 题目描述 小\(\mathrm{G}\)的喜欢作画,尤其喜欢仅使用黑白两色作画. 画作可以抽象成一个\(r\times c\)大小的\(01\)矩阵.现在小\(\mathrm{G}\)构思好了他 ...

  9. php56升级后php7 mcrypt_encrypt 报错

    mcrypt_encrypt(MCRYPT_BLOWFISH, $passphrase, $data, MCRYPT_MODE_CBC, $iv); openssl_encrypt($data, &q ...

  10. vue项目--favicon设置以及动态修改favicon

    最近写公司项目时,动态更新favicon 动态更新之前需要有一个默认的favicon. 目前vue-cli搭建的vue项目里面已经有了一个static文件夹,存放静态文件. favicon图片放到该文 ...