ZROI 2019 寒假省选线下自闭赛2

Posted aegir

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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
", 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 }

 

以上是关于ZROI 2019 寒假省选线下自闭赛2的主要内容,如果未能解决你的问题,请参考以下文章

0118ACM自闭赛

寒假总结和省选大体规划

省选联考 2023 同步赛

2020.1.29 寒假训练赛2

2020.2.8铁一寒假收官赛题解

10.20字符串自闭赛