• [BZOJ5289][HNOI2018]排列(拓扑排序+pb_ds)


    首先确定将所有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两个点。

     1 #include<cstdio>
     2 #include<queue>
     3 #include<algorithm>
     4 #define rep(i,l,r) for (int i=(l); i<=(r); i++)
     5 typedef long long ll;
     6 using namespace std;
     7 
     8 const int N=500100;
     9 int n,u,p,fa[N],tim,cnt,vis[N],f[N],sz[N],h[N],nxt[N<<1],to[N<<1];
    10 ll ans,w[N];
    11 struct D{ int u,sz; ll w; bool operator <(const D &b)const{ return w*b.sz>b.w*sz; } };
    12 priority_queue<D>Q;
    13 
    14 void add(int u,int v){ to[++cnt]=v; nxt[cnt]=h[u]; h[u]=cnt; }
    15 
    16 void dfs(int u){
    17     vis[u]=1; tim++;
    18     for (int i=h[u],v; i; i=nxt[i])
    19         if (vis[v=to[i]]) { puts("-1"); exit(0); } else dfs(v);
    20 }
    21 
    22 int get(int x){ return (f[x]==x) ? x : f[x]=get(f[x]); }
    23 
    24 int main(){
    25     freopen("bzoj5289.in","r",stdin);
    26     freopen("bzoj5289.out","w",stdout);
    27     scanf("%d",&n);
    28     rep(i,1,n) scanf("%d",&fa[i]),add(fa[i],i);
    29     dfs(0); if (tim<=n) { puts("-1"); return 0; }
    30     rep(i,0,n) f[i]=i,sz[i]=1;
    31     rep(i,1,n) scanf("%lld",&w[i]),Q.push((D){i,1,w[i]});
    32     while (!Q.empty()){
    33         D s=Q.top(); Q.pop();
    34         if (sz[u=get(s.u)]!=s.sz) continue;
    35         f[u]=p=get(fa[u]); ans+=w[u]*sz[p];
    36         w[p]+=w[u]; sz[p]+=sz[u];
    37         if (p) Q.push((D){p,sz[p],w[p]});
    38     }
    39     printf("%lld
    ",ans);
    40     return 0;
    41 }

    二:STL-set

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

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

     1 #include<cstdio>
     2 #include<set>
     3 #include<algorithm>
     4 #define rep(i,l,r) for (int i=(l); i<=(r); i++)
     5 typedef long long ll;
     6 using namespace std;
     7 
     8 const int N=500100;
     9 int n,u,p,fa[N],tim,cnt,vis[N],f[N],sz[N],h[N],nxt[N<<1],to[N<<1];
    10 ll ans,w[N];
    11 struct D{
    12     int u,sz; ll w;
    13     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)); }
    14 };
    15 multiset<D>Q;
    16 
    17 void add(int u,int v){ to[++cnt]=v; nxt[cnt]=h[u]; h[u]=cnt; }
    18 
    19 void dfs(int u){
    20     vis[u]=1; tim++;
    21     for (int i=h[u],v; i; i=nxt[i])
    22         if (vis[v=to[i]]) { puts("-1"); exit(0); } else dfs(v);
    23 }
    24 
    25 int get(int x){ return (f[x]==x) ? x : f[x]=get(f[x]); }
    26 
    27 int main(){
    28     freopen("bzoj5289.in","r",stdin);
    29     freopen("bzoj5289.out","w",stdout);
    30     scanf("%d",&n);
    31     rep(i,1,n) scanf("%d",&fa[i]),add(fa[i],i);
    32     dfs(0); if (tim<=n) { puts("-1"); return 0; }
    33     rep(i,0,n) f[i]=i,sz[i]=1;
    34     rep(i,1,n) scanf("%lld",&w[i]),Q.insert((D){i,1,w[i]});
    35     while (!Q.empty()){
    36         D s=*Q.begin(); Q.erase(s);
    37         if (sz[u=get(s.u)]!=s.sz) continue;
    38         f[u]=p=get(fa[u]); ans+=w[u]*sz[p];
    39         w[p]+=w[u]; sz[p]+=sz[u];
    40         if (p) Q.insert((D){p,sz[p],w[p]});
    41     }
    42     printf("%lld
    ",ans);
    43     return 0;
    44 }

    三:__gnu_pbds::priority_queue

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

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

    BZOJ上AC,Luogu上AC。

     1 #include<cstdio>
     2 #include<ext/pb_ds/assoc_container.hpp>
     3 #include<ext/pb_ds/priority_queue.hpp>
     4 #include<algorithm>
     5 #define rep(i,l,r) for (int i=(l); i<=(r); i++)
     6 typedef long long ll;
     7 using namespace std;
     8 
     9 const int N=500100;
    10 int n,u,p,fa[N],tim,cnt,vis[N],f[N],sz[N],h[N],nxt[N<<1],to[N<<1];
    11 ll ans,w[N];
    12 struct D{ int u; ll w; };
    13 struct Cmp{
    14     bool operator()(const D &a,const D &b)const
    15     { 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])); }
    16 };
    17 __gnu_pbds::priority_queue<D,Cmp>Q;
    18 __gnu_pbds::priority_queue<D,Cmp>::point_iterator its[N];
    19 
    20 void add(int u,int v){ to[++cnt]=v; nxt[cnt]=h[u]; h[u]=cnt; }
    21 
    22 void dfs(int u){
    23     vis[u]=1; tim++;
    24     for (int i=h[u],v; i; i=nxt[i])
    25         if (vis[v=to[i]]) { puts("-1"); exit(0); } else dfs(v);
    26 }
    27 
    28 int get(int x){ return (f[x]==x) ? x : f[x]=get(f[x]); }
    29 
    30 int main(){
    31     freopen("bzoj5289.in","r",stdin);
    32     freopen("bzoj5289.out","w",stdout);
    33     scanf("%d",&n);
    34     rep(i,1,n) scanf("%d",&fa[i]),add(fa[i],i);
    35     dfs(0); if (tim<=n) { puts("-1"); return 0; }
    36     rep(i,0,n) f[i]=i,sz[i]=1;
    37     rep(i,1,n) scanf("%lld",&w[i]),its[i]=Q.push((D){i,w[i]});
    38     while (!Q.empty()){
    39         int u=Q.top().u; Q.pop();
    40         f[u]=p=get(fa[u]); ans+=w[u]*sz[p];
    41         w[p]+=w[u]; sz[p]+=sz[u];
    42         if (p) Q.modify(its[p],(D){p,w[p]});
    43     }
    44     printf("%lld
    ",ans);
    45     return 0;
    46 }
  • 相关阅读:
    leetcode--Remove Duplicates from Sorted Array
    leetcode--Valid Parentheses
    leetcode--Longest Substring Without Repeating Characters
    leetcode--Combination Sum
    leetcode--Valid Sudoku
    java 4对象群体的组织
    java 3 接口与多态&输入输出流
    java 3类的继承
    java 2类与对象[学堂在线]
    计算机网络{网页开发与服务配置}
  • 原文地址:https://www.cnblogs.com/HocRiser/p/8963848.html
Copyright © 2020-2023  润新知