[HNOI/AHOI2018] Arrangement

The main idea of ​​the title:
  Given $n(n\le5\times10^5)$ positive integers $a_1, a_2, \ldots, a_n(0\le a_i\le n)$, and $n$ positive integers $w_1, w_2,\ldots,w_n$. A permutation of $a$$a_{p[1]},a_{p[2]},\ldots,a_{p[n]}$ is said to be a legal permutation if and only if the permutation satisfies: for any $ k$ and $j$, if $j\le k$, $a_{p[j]}\ne p[k]$. The weight that defines this legal permutation is $\sum w_{p[i]}\times i$. Ask if there is a legal permutation. If so, find the maximum weight.

Idea:
  Connect the edges $a_i\to i$, obviously a permutation is legal if and only if the permutation is a topological order of the graph. That is, if there is a ring, the legal arrangement does not exist.
  For cases where there are legal permutations, the point with the smallest w_i$ is greedily selected each time. If the in-degree of $i$ is $0$ after removing the selected points in the figure, then selecting $i$ must be optimal at this time. If $i$ cannot be selected now, then $a_i$ will be given priority. If $a_i$ is selected later, it will be better to choose $i$ immediately. You can use union search to merge $i$ into $a_i$. Note that $a_i$ may also depend on other nodes, and there may be nodes that depend on $i$, so the entire connected block containing dependencies needs to be maintained when merging. The priority of the merged nodes needs to be adjusted accordingly, which can justify the comparison with the average value of the elements in the block. This can obviously be maintained by the heap, and the time complexity is $O(n\log n)$.

 1 #include<queue>
 2 #include<cstdio>
 3 #include<cctype>
 4 #include<functional>
 5 #include<ext/pb_ds/priority_queue.hpp>
 6 typedef long long int64;
 7 inline int getint() {
 8     register char ch;
 9     while(!isdigit(ch=getchar()));
10     register int x=ch^'0';
11     while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0');
12     return x;
13 }
14 const int N=5e5+1;
15 int n,a[N],h[N],sz,size[N],cnt;
16 int64 w[N];
17 struct Edge {
18     int to,next;
19 };
20 Edge e[N];
21 inline void add_edge(const int &u,const int &v) {
22     e[++sz]=(Edge){v,h[u]};h[u]=sz;
23 }
24 bool vis[N];
25 bool dfs(const int &x) {
26     if(vis[x]) return false;
27     vis[x]=true;
28     cnt++;
29     for(int i=h[x];i;i=e[i].next) {
30         const int &y=e[i].to;
31         if(!dfs(y)) return false;
32     }
33     return true;
34 }
35 inline bool check() {
36     dfs(0);
37     return cnt==n+1;
38 }
39 struct Node {
40     int id;
41     bool operator > (const Node &another) const {
42         return w[id]*size[another.id]>w[another.id]*size[id];
43     }
44 };
45 __gnu_pbds::priority_queue<Node,std::greater<Node> > q;
46 __gnu_pbds::priority_queue<Node,std::greater<Node> >::point_iterator p[N];
47 struct DisjointSet {
48     int anc[N];
49     int find(const int &x) {
50         return x==anc[x]?x:anc[x]=find(anc[x]);
51     }
52     void reset(const int &n) {
53         for(register int i=0;i<=n;i++) anc[i]=i;
54     }
55     void merge(const int &x,const int &y) {
56         anc[find(x)]=find(y);
57     }
58 };
59 DisjointSet s;
60 inline int64 solve() {
61     if(!check()) return -1;
62     for(register int i=size[0]=1;i<=n;i++) {
63         size[i]=1;
64         p[i]=q.push((Node){i});
65     }
66     s.reset(n);
67     int64 ret=0;
68     for(register int i=1;i<=n;i++) {
69         const int x=q.top().id,par=s.find(a[x]);
70         s.merge(x,par);
71         q.pop();
72         ret+=w[x]*size[par];
73         w[par]+=w[x];
74         size[par]+=size[x];
75         if(par) q.modify(p[par],(Node){par});
76     }
77     return ret;
78 }
79 int main() {
80     n=getint();
81     for(register int i=1;i<=n;i++) {
82         add_edge(a[i]=getint(),i);
83     }
84     for(register int i=1;i<=n;i++) {
85         w[i]=getint();
86     }
87     printf("%lld\n",solve());
88     return 0;
89 }

 

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=324621134&siteId=291194637