ZROI 2019 寒假省选线下自闭赛2
作者:互联网
预计&实际得分:$20 + 20 + 40 = 80$
emmmm暴力总算没有写炸了,不过也只会写暴力了。。。
T1:
不会,,打个表$20$分走人
T2:
不会,$N≤3$的时候手算一下,$a_i=a_0$的时候所有的$P_i$都是$\frac{\sqrt{a_0}}{n}$,这样就有$30分$了(考试的时候$N=3$的情况没算出来)
T3:
其实我主要是想写一下这个题。
首先我们$O(n)$枚举一下点,然后我们规定必须要选这个点。
对于其他的点$i$,如果我们要选$i$的话,那么我们肯定要选$i$在两颗子树中的父亲节点。
于是我们连边$i->f_1[i]$和$i->f_2[i]$($f_1[i], f_2[i]$分别表示$i$在两颗树上的父亲)
注意我们这里连的都是有向边。
这样问题就变成了:给定一个有向图,其中每个点都有一个权值,选择一个权值和最大的子图,使得每个点的后继都在子图里面。
这其实就是裸的最大权闭合子图问题,用网络流求解即可。
1 #include<bits/stdc++.h> 2 using namespace std; 3 4 const int MAXN = 510; 5 6 struct Dinic 7 { 8 struct Edge 9 { 10 int from, to; 11 int cap, flow; 12 }; 13 vector<Edge> edges; 14 vector<int> G[MAXN]; 15 int n, m, s, t; 16 bool v[MAXN]; 17 int d[MAXN], cur[MAXN]; 18 19 void Clear() 20 { 21 edges.clear(); m = 0; 22 for(int i = 0; i < MAXN; ++i) G[i].clear(); 23 } 24 25 void add(int from, int to, int cap) 26 { 27 edges.push_back((Edge){from, to, cap, 0}); 28 edges.push_back((Edge){to, from, 0, 0}); 29 G[from].push_back(m++); 30 G[to].push_back(m++); 31 } 32 33 bool bfs() 34 { 35 memset(v, 0, sizeof(v)); 36 memset(d, -1, sizeof(d)); 37 queue<int> q; q.push(s); 38 d[s] = 1; v[s] = 1; 39 while(!q.empty()) 40 { 41 int x = q.front(); q.pop(); 42 for(int i = 0; i < (int)G[x].size(); ++i) 43 { 44 Edge e = edges[G[x][i]]; 45 if(!v[e.to] && e.cap > e.flow) 46 { 47 v[e.to] = 1; 48 d[e.to] = d[x] + 1; 49 q.push(e.to); 50 } 51 } 52 } 53 return v[t]; 54 } 55 56 int DFS(int x, int a) 57 { 58 if(x == t || !a) return a; 59 int flow = 0, f; 60 for(int& i = cur[x]; i < (int)G[x].size(); ++i) 61 { 62 Edge& e = edges[G[x][i]]; 63 if(d[e.to] == d[x] + 1 && (f = DFS(e.to, min(a, e.cap - e.flow))) > 0) 64 { 65 e.flow += f; 66 edges[G[x][i] ^ 1].flow -= f; 67 flow += f; 68 a -= f; 69 if(!a) break; 70 } 71 } 72 return flow; 73 } 74 75 int Maxflow() 76 { 77 int flow = 0; 78 while(bfs()) 79 { 80 memset(cur, 0, sizeof(cur)); 81 flow += DFS(s, 0x7FFFFFFF); 82 } 83 return flow; 84 } 85 }din; 86 87 vector<int> G1[MAXN], G2[MAXN]; 88 int f1[MAXN], f2[MAXN]; 89 int T, n, a[MAXN]; 90 91 void dfs1(int x, int fa) 92 { 93 f1[x] = fa; 94 for(int i = 0; i < (int)G1[x].size(); ++i) 95 if(G1[x][i] != fa) dfs1(G1[x][i], x); 96 } 97 98 void dfs2(int x, int fa) 99 { 100 f2[x] = fa; 101 for(int i = 0; i < (int)G2[x].size(); ++i) 102 if(G2[x][i] != fa) dfs2(G2[x][i], x); 103 } 104 105 void solve() 106 { 107 int sum = 0, ans = 0; 108 for(int i = 1; i <= n; ++i) 109 if(a[i] > 0) sum += a[i]; 110 din.s = n + n + 1, din.t = din.s + 1; 111 for(int root = 1; root <= n; ++root) 112 { 113 dfs1(root, 0); 114 dfs2(root, 0); 115 din.Clear(); 116 for(int i = 1; i <= n; ++i) 117 { 118 if(a[i] > 0) din.add(din.s, i, a[i]); 119 else din.add(i, din.t, -a[i]); 120 if(f1[i]) din.add(i, f1[i], 0x3f3f3f3f); 121 if(f2[i]) din.add(i, f2[i], 0x3f3f3f3f); 122 } 123 ans = max(ans, sum - din.Maxflow()); 124 } 125 printf("%d\n", ans); 126 } 127 128 int main() 129 { 130 scanf("%d", &T); 131 while(T--) 132 { 133 scanf("%d", &n); 134 for(int i = 1; i <= n; ++i) 135 { 136 scanf("%d", &a[i]); 137 G1[i].clear(); 138 G2[i].clear(); 139 } 140 for(int i = 1, u, v; i < n; ++i) 141 { 142 scanf("%d %d", &u, &v); 143 G1[u].push_back(v); 144 G1[v].push_back(u); 145 } 146 for(int i = 1, u, v; i < n; ++i) 147 { 148 scanf("%d %d", &u, &v); 149 G2[u].push_back(v); 150 G2[v].push_back(u); 151 } 152 solve(); 153 } 154 return 0; 155 }
标签:din,int,flow,++,自闭,edges,2019,MAXN,ZROI 来源: https://www.cnblogs.com/Aegir/p/10388157.html