「SNOI2019」通信 分治优化费用流建图

题意:

n 个排成一列的哨站要进行通信。第 i 个哨站的频段为 ai

每个哨站 ii 需要选择以下二者之一:

1.直接连接到控制中心,代价为 W
2.连接到前面的某个哨站 j(j|ai−aj|。 每个哨站只能被后面的至多一个哨站连接。

请你求出最小可能的代价和。

 

题解:

显然的费用流

然后我耿直的n^2建边,觉得我的费用流很快,应该可以过

然后返回了TLE 

然后google了一下题解:发现这题卡了n^2建图,需要优化建边

我这里是通过分治优化的

就是类似与建立一个虚点

一个x要向y的一个前缀建图,所以就可以类似前缀和优化建图那样,

按权值排序然后建出一条链,链上两个点之间的流量为INF,费用为权值之差,然后每个点向对应的点连边
但这样建图是错误的,原因在于我们把点排了序,改变了编号顺序,

所以一个点能到达的点不一定是它可以到达的
所以我们要固定在固定编号顺序的情况下这样连边,也就是说x的一个区间和y的一个区间之间这样连边,

要求两个区间不重合,且x的区间比y的区间小
那么很容易想到分治建图,每次让[l,mid]向[mid+1,r]连边,剩下的递归下去就行了

  1 #include <set>
  2 #include 
  3 #include 
  4 #include 
  5 #include 
  6 #include 
  7 #include 
  8 #include <string>
  9 #include 
 10 #include 
 11 #include 
 12 #include 
 13 #include 
 14 
 15 #define pi acos(-1.0)
 16 #define eps 1e-9
 17 #define fi first
 18 #define se second
 19 #define rtl rt << 1
 20 #define rtr rt << 1 | 1
 21 #define bug printf("******\n")
 22 #define mem(a, b) memset(a, b, sizeof(a))
 23 #define name2str(x) #x
 24 #define fuck(x) cout << #x " = " << x << endl
 25 #define sfi(a) scanf("%d", &a)
 26 #define sffi(a, b) scanf("%d %d", &a, &b)
 27 #define sfffi(a, b, c) scanf("%d %d %d", &a, &b, &c)
 28 #define sffffi(a, b, c, d) scanf("%d %d %d %d", &a, &b, &c, &d)
 29 #define sfL(a) scanf("%lld", &a)
 30 #define sffL(a, b) scanf("%lld %lld", &a, &b)
 31 #define sfffL(a, b, c) scanf("%lld %lld %lld", &a, &b, &c)
 32 #define sffffL(a, b, c, d) scanf("%lld %lld %lld %lld", &a, &b, &c, &d)
 33 #define sfs(a) scanf("%s", a)
 34 #define sffs(a, b) scanf("%s %s", a, b)
 35 #define sfffs(a, b, c) scanf("%s %s %s", a, b, c)
 36 #define sffffs(a, b, c, d) scanf("%s %s %s %s", a, b, c, d)
 37 #define FIN freopen("../in.txt", "r", stdin)
 38 #define gcd(a, b) __gcd(a, b)
 39 #define lowbit(x) x & -x
 40 #define IO iOS::sync_with_stdio(false)
 41 
 42 using namespace std;
 43 typedef long long LL;
 44 typedef unsigned long long ULL;
 45 const ULL seed = 13331;
 46 const LL INFLL = 0x3f3f3f3f3f3f3f3fLL;
 47 const int maxn = 1e6 + 7;
 48 const int maxm = 8e6 + 10;
 49 const int INF = 0x3f3f3f3f;
 50 const int mod = 1e9 + 7;
 51 
 52 struct Cost_MaxFlow {
 53     int s, t, tot, maxflow, head[maxn], vis[maxn], pre[maxn], last[maxn];
 54     LL mincost, maxcost, dis[maxn], disf[maxn];
 55     struct Edge {
 56         int v, w, nxt;
 57         int cost;
 58     } edge[maxm];
 59     queue<int> q;
 60 
 61     void init() {
 62         tot = 1;
 63         mincost = maxcost = 0;
 64         memset(head, -1, sizeof(head));
 65     }
 66 
 67     void add(int u, int v, int f, int e) {
 68         edge[++tot].v = v, edge[tot].nxt = head[u], head[u] = tot, edge[tot].w = f, edge[tot].cost = e;
 69         edge[++tot].v = u, edge[tot].nxt = head[v], head[v] = tot, edge[tot].w = 0, edge[tot].cost = -e;
 70     }
 71 
 72     bool spfa_max() {
 73         memset(dis, 0xef, sizeof(dis));
 74         q.push(s), dis[s] = 0, disf[s] = INFLL, pre[t] = -1;
 75         while (!q.empty()) {
 76             int u = q.front();
 77             q.pop();
 78             vis[u] = 0;
 79             for (int i = head[u]; ~i; i = edge[i].nxt) {
 80                 int v = edge[i].v;
 81                 if (edge[i].w && dis[v] < dis[u] + edge[i].cost) {
 82                     dis[v] = dis[u] + edge[i].cost, last[v] = i, pre[v] = u;
 83                     disf[v] = min(disf[u], 1LL * edge[i].w);
 84                     if (!vis[v])
 85                         vis[v] = 1, q.push(v);
 86                 }
 87             }
 88         }
 89         return ~pre[t];
 90     }
 91 
 92     void dinic_max() {
 93         while (spfa_max()) {
 94             int u = t;
 95             maxflow += disf[t];
 96             maxcost += disf[t] * dis[t];
 97             while (u != s) {
 98                 edge[last[u]].w -= disf[t];
 99                 edge[last[u] ^ 1].w += disf[t];
100                 u = pre[u];
101             }
102         }
103     }
104 
105     bool spfa_min() {
106         memset(dis, 0x3f, sizeof(dis));
107         memset(vis, 0, sizeof(vis));
108         memset(disf, 0x3f, sizeof(disf));
109         q.push(s), dis[s] = 0, vis[s] = 1, pre[t] = -1;
110         while (!q.empty()) {
111             int u = q.front();
112             q.pop();
113             vis[u] = 0;
114             for (int i = head[u]; ~i; i = edge[i].nxt) {
115                 int v = edge[i].v;
116                 if (edge[i].w > 0 && dis[v] > dis[u] + edge[i].cost) {
117                     dis[v] = dis[u] + edge[i].cost, pre[v] = u;
118                     last[v] = i, disf[v] = min(disf[u], 1LL * edge[i].w);
119                     if (!vis[v])
120                         vis[v] = 1, q.push(v);
121                 }
122             }
123         }
124         return pre[t] != -1;
125     }
126 
127     void dinic_min() {
128         while (spfa_min()) {
129             int u = t;
130             maxflow += disf[t];
131             mincost += disf[t] * dis[t];
132             while (u != s) {
133                 edge[last[u]].w -= disf[t];
134                 edge[last[u] ^ 1].w += disf[t];
135                 u = pre[u];
136             }
137         }
138     }
139 } F;
140 
141 int n, W, a[maxn], cnt[maxn], sum;
142 
143 void link(int L, int R) {
144     if (L == R) return;
145     int num = 0, mid = (L + R) / 2;
146     for (int i = L; i <= R; i++) cnt[++num] = a[i];
147     sort(cnt + 1, cnt + 1 + num);
148     num = unique(cnt + 1, cnt + 1 + num) - cnt - 1;
149     for (int i = 1; i < num; i++) {
150         F.add(sum + i, sum + i + 1, INF, cnt[i + 1] - cnt[i]);
151         F.add(sum + i + 1, sum + i, INF, cnt[i + 1] - cnt[i]);
152     }
153     for (int i = L; i <= R; i++) {
154         if (i <= mid) {
155             int pos = lower_bound(cnt + 1, cnt + 1 + num, a[i]) - cnt;
156             F.add(sum + pos, i + n, 1, 0);
157         } else {
158             int pos = lower_bound(cnt + 1, cnt + 1 + num, a[i]) - cnt;
159             F.add(i, sum + pos, 1, 0);
160         }
161     }
162     sum += num;
163     link(L, mid), link(mid + 1, R);
164 }
165 
166 int main() {
167 #ifndef ONLINE_JUDGE
168     FIN;
169 #endif
170     while (~sffi(n, W)) {
171         for (int i = 1; i <= n; i++) sfi(a[i]);
172         F.init();
173         F.s = 0, F.t = 2 * n + 1;
174         sum = 2 * n + 1;
175         for (int i = 1; i <= n; i++) {
176             F.add(F.s, i, 1, 0);
177             F.add(i + n, F.t, 1, 0);
178             F.add(i, F.t, 1, W);
179         }
180         link(1, n);
181         F.dinic_min();
182         printf("%lld\n", F.mincost);
183     }
184 #ifndef ONLINE_JUDGE
185     cout << "Totle Time : " << (double) clock() / CLOCKS_PER_SEC << "s" << endl;
186 #endif
187     return 0;
188 }
View Code

 

你可能感兴趣的:(「SNOI2019」通信 分治优化费用流建图)