题面描述的相当绕,其实就是如果ai=j,重排后ai要在aj之后。同时每个ai有附属属性wi,要求最大化重排后的Σiwi。
容易发现这事实上构成一张图,即由j向i连边。由于每个点入度为1或0,该图是基环外向树森林,并且如果图中有环显然无解,所以这张图就是个森林。把0也看做一个点后变成一棵树。由于其是基环树判环并查集就够了。
问题变为对该树找一个删点的顺序使价值最大,要求删了父亲才能删儿子。显然应该尽量先删价值小的,但直接贪心肯定不对。
如果树中的最小值的父亲此时已经被删,立即将其删除一定是最优的。那么不妨考虑将这两个点合并。稍微推一下式子可以发现合并后用权值平均值作为新权值(不是贡献)即可。堆维护。
#include<iostream> #include<cstdio> #include<cmath> #include<cstdlib> #include<cstring> #include<algorithm> #include<queue> #include<cassert> using namespace std; #define ll long long #define N 500010 char getc(){char c=getchar();while ((c<'A'||c>'Z')&&(c<'a'||c>'z')&&(c<'0'||c>'9')) c=getchar();return c;} int gcd(int n,int m){return m==0?n:gcd(m,n%m);} int read() { int x=0,f=1;char c=getchar(); while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();} while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar(); return x*f; } int n,a[N],fa[N],f[N],p[N],t; ll ans; bool flag[N]; struct data{int to,nxt; }edge[N]; struct data2 { int id,cnt;ll tot,val; bool operator <(const data2&a) const { return tot*a.cnt>a.tot*cnt; } bool operator !=(const data2&a) const { return id!=a.id||cnt!=a.cnt||tot!=a.tot||val!=a.val; } }lazy[N]; priority_queue<data2> q; void addedge(int x,int y){t++;edge[t].to=y,edge[t].nxt=p[x],p[x]=t;} int find(int x){return fa[x]==x?x:fa[x]=find(fa[x]);} void dfs(int k) { for (int i=p[k];i;i=edge[i].nxt) f[edge[i].to]=k,dfs(edge[i].to); } int main() { #ifndef ONLINE_JUDGE freopen("bzoj5289.in","r",stdin); freopen("bzoj5289.out","w",stdout); const char LL[]="%I64d "; #else const char LL[]="%lld "; #endif n=read(); for (int i=0;i<=n;i++) fa[i]=i; for (int i=1;i<=n;i++) { int x=read();addedge(x,i); int p=find(x),q=find(i); if (p!=q) fa[q]=p;else {cout<<-1;return 0;} } dfs(0); for (int i=1;i<=n;i++) { a[i]=read(),fa[i]=i; lazy[i]=(data2){i,1,a[i],a[i]};q.push(lazy[i]); } flag[0]=1;fa[0]=0;int cnt=0; for (int i=1;i<=n;i++) { while (q.top()!=lazy[q.top().id]) q.pop(); data2 x=q.top();q.pop();int u=find(f[x.id]);fa[x.id]=u; if (flag[u]) ans+=x.val+cnt*x.tot,cnt+=x.cnt,flag[x.id]=1; else lazy[u].val+=lazy[u].cnt*x.tot+x.val,lazy[u].id=u,lazy[u].cnt+=x.cnt,lazy[u].tot+=x.tot,q.push(lazy[u]); } cout<<ans; return 0; }