[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\n",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\n",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\n",ans);
45     return 0;
46 }

 

posted @ 2018-04-27 18:17  HocRiser  阅读(306)  评论(0编辑  收藏  举报