题目链接:http://www.51nod.com/Challenge/Problem.html#!#problemId=2564
令 A A A为染成白色的集合, B B B为染成黑色的集合 C C C为被惩罚的集合
a n s = max A , B ( ∑ k ∈ A w ( k ) ) + ∑ k ∈ B b ( k ) − ∑ k ∈ C P ( i ) ) = ∑ k = 1 n ( w ( k ) + b ( k ) ) − m i n ( ∑ k ∈ A b ( k ) + ∑ k ∈ B w ( k ) + ∑ k ∈ C P ( i ) ) ans = \max_{A,B}\Big(\sum_{k\in A}w(k))+\sum_{k\in B}b(k)-\sum_{k\in C}P(i)\Big)\\ = \sum_{k=1}^n\Big(w(k)+b(k)\Big)-min\Big(\sum_{k\in A}b(k)+\sum_{k\in B}w(k) +\sum_{k\in C}P(i)\Big) ans=A,Bmax(k∈A∑w(k))+k∈B∑b(k)−k∈C∑P(i))=k=1∑n(w(k)+b(k))−min(k∈A∑b(k)+k∈B∑w(k)+k∈C∑P(i))
问题关键是极小化:
∑ k ∈ A b ( k ) + ∑ k ∈ B w ( k ) + ∑ k ∈ C P ( i ) \sum_{k\in A}b(k)+\sum_{k\in B}w(k) +\sum_{k\in C}P(i) k∈A∑b(k)+k∈B∑w(k)+k∈C∑P(i)
那么现在问题相当于最小化上述式子,其中,点 i i i选择白色的点后,如果之前存在点 k k k有: k < i l ( i ) ≤ a ( k ) ≤ r ( i ) k<i\\ l(i)\leq a(k) \leq r(i) k<il(i)≤a(k)≤r(i)
那么这个点贡献增加 P ( i ) P(i) P(i)
考虑网络流:
s → i , f = b ( i ) i → t , f = w ( i ) i → i ′ , f = P ( i ) i ′ → k , f = ∞ s\rightarrow i ,f=b(i)\\ i\rightarrow t ,f=w(i)\\ i\rightarrow i' ,f=P(i)\\ i'\rightarrow k ,f=∞ s→i,f=b(i)i→t,f=w(i)i→i′,f=P(i)i′→k,f=∞
其中 k k k为当 i i i选白色后,可以让 i i i的贡献提升的点。
这样当运行最大流算法时:
如果 w ( i ) ≥ b ( i ) w(i)\geq b(i) w(i)≥b(i),则 b ( i ) b(i) b(i)所在边一定会被充满。
若此时, w ( i ) < b ( i ) w(i)<b(i) w(i)<b(i),则 p ( i ) , w ( i ) p(i),w(i) p(i),w(i)至少有一条路线会满流。
假设有 p ( i ) , b ( i ) p(i),b(i) p(i),b(i)都没有满,且所有的 b ( k ) b(k) b(k)都满.那么此时所有 w ( k ) w(k) w(k)一定也满,这是因为如果 w ( k ) w(k) w(k)不满,则矛盾,此时算法为达到最大流。
这也就是说,当 w ( i ) w(i) w(i)满, b ( i ) b(i) b(i)不满,若之前有 b ( k ) b(k) b(k)满,则 w ( k ) w(k) w(k)一定满,否则 p ( i ) p(i) p(i)满流。
考虑最大流最小割。此时相当于得到了最小割集。
f l o w = ∑ k ∈ A b ( k ) + ∑ k ∈ B w ( k ) + ∑ k ∈ C P ( i ) flow=\sum_{k\in A}b(k)+\sum_{k\in B}w(k) +\sum_{k\in C}P(i) flow=k∈A∑b(k)+k∈B∑w(k)+k∈C∑P(i)
那么: a n s = ∑ k = 1 n ( b ( k ) + w ( k ) ) − f l o w ans = \sum_{k=1}^n\Big(b(k)+w(k)\Big)-flow ans=∑k=1n(b(k)+w(k))−flow
由于 n n n太大了,建图过于耗费内存。而多数重复的边都是无穷流量的。所以可以把很多边缩到一个点上,去联接。对于某一块 m m m个点与 n n n另外 d d d个点链接边数可以变为 n + d n+d n+d.
可以利用持久化线段时。并向所在区间的树节点连边。
#include
#include
#include
#include
const int maxn = 5005;
const int coe = 32;
const int INF = 0x3f3f3f3f;
using namespace std;
int maxFlow2(int source, int sink);
int maxFlow(int source, int sink);
struct node
{
int c[2];
node() { c[0] = c[1] = 0; }
};
struct edge_node
{
int f, fir, nxt, to;
edge_node() {}
};
int g_size = maxn*coe;
int Head[maxn*coe * 3];
node Node[maxn*coe];
edge_node EdgeNode[maxn*coe * 3];
int L[maxn];
int R[maxn];
int a[maxn];
int b[maxn];
int w[maxn];
int p[maxn];
int tmpMemory[maxn * 3];
int deep = 1;
int deep_edge;
int n, n2;
void addEdge_ex(int from, int to, int flow);
void addEdge(int from, int to, int flow = INF)
{
#ifdef _DEBUG
if (from >= maxn*coe)printf("error\n");
if (to >= maxn*coe)printf("error\n");
#endif // _DEBUG
if (!flow)return;
addEdge_ex(from, to, flow);
addEdge_ex(to, from, 0);
}
void addEdge_ex(int from, int to, int flow)
{
EdgeNode[deep_edge].f = flow;
EdgeNode[deep_edge].to = to;
EdgeNode[deep_edge].nxt = Head[from];
if (Head[from] > -1)EdgeNode[Head[from]].fir = deep_edge;
EdgeNode[deep_edge].fir = -1;
Head[from] = deep_edge++;
}
void reduce(int from, edge_node &e)
{
if (e.fir == -1)
Head[from] = e.nxt;
else
EdgeNode[e.fir].nxt = e.nxt;
if (e.nxt > -1)
EdgeNode[e.nxt].fir = e.fir;
}
void addTree(int A, int l, int r, int last, int &k, int now, int pro = 0)
{
if (!last)
{
if (A < l)return;
if (A > r)return;
if (!k)
{
k = deep++;
if (pro)
addEdge(pro + n2, k + n2);
}
if (l == r)
{
addEdge(k + n2, now);
return;
}
int mid = (l + r) >> 1;
addTree(A, l, mid, 0, Node[k].c[0], now, k);
addTree(A, mid + 1, r, 0, Node[k].c[1], now, k);
return;
}
if (A < l)return;
if (A > r)return;
if (!k)
{
k = deep++;
if (pro)
addEdge(pro + n2, k + n2);
}
if (l == r)
{
addEdge(k + n2, now);
addEdge(k + n2, last + n2);
return;
}
int mid = (l + r) >> 1;
Node[k].c[!(A > mid)] = Node[last].c[!(A > mid)];
if (Node[last].c[!(A > mid)])addEdge(k + n2, Node[last].c[!(A > mid)] + n2);
if (A > mid)
addTree(A, mid + 1, r, Node[last].c[1], Node[k].c[1], now, k);
else
addTree(A, l, mid, Node[last].c[0], Node[k].c[0], now, k);
return;
}
void link_Tree_Edge(int root, int index, int l, int r, int nL, int nR)
{
if (!root)return;
if (nR < l)return;
if (nL > r)return;
if (l <= nL&&nR <= r)
{
addEdge(index, root + n2);
return;
}
int mid = (nL + nR) >> 1;
link_Tree_Edge(Node[root].c[0], index, l, r, nL, mid);
link_Tree_Edge(Node[root].c[1], index, l, r, mid + 1, nR);
}
int main()
{
#ifdef _DEBUG
//freopen("C:\\Users\\Administrator\\Downloads\\51nod_2564_4_in.txt", "r", stdin);
#endif
//freopen("C:\\Users\\Administrator\\Downloads\\51nod_2564_9_in.txt", "r", stdin);
memset(Head, -1, sizeof Head);
int maxR = -1;
scanf("%d", &n);
n2 = n * 2;
#ifdef _DEBUG
printf("n : %d\n", n);
#endif // _DEBUG
long long total = 0;
#if 0
n = 5000;
n2 = n * 2;
srand(213089139);
for (int i = 0;i < n;i++)
{
if (i < n / 2)
{
b[i] = 20 + rand() % 10;
w[i] = 33 + rand() % 10;
p[i] = b[i] - w[i];
}
else
{
b[i] = w[i - n / 2];
w[i] = b[i - n / 2];
p[i] = b[i] - w[i];
}
tmpMemory[i * 3] = L[i] = 0;
tmpMemory[i * 3 + 1] = R[i] = i;
tmpMemory[i * 3 + 2] = a[i] = i % 2;
total += b[i] + w[i];
}
#else
for (int i = 0;i < n;i++)
{
scanf("%d%d%d%d%d%d", a + i, b + i, w + i, L + i, R + i, p + i);
tmpMemory[i * 3] = L[i];
tmpMemory[i * 3 + 1] = R[i];
tmpMemory[i * 3 + 2] = a[i];
total += b[i] + w[i];
}
#endif // _DEBUG
#ifdef _DEBUG
printf("OK\n");
#endif // _DEBUG
sort(tmpMemory, tmpMemory + n * 3);
int count = int(unique(tmpMemory, tmpMemory + n * 3) - tmpMemory);
for (int i = 0;i < n;i++)
{
L[i] = int(lower_bound(tmpMemory, tmpMemory + count, L[i]) - tmpMemory);
R[i] = int(lower_bound(tmpMemory, tmpMemory + count, R[i]) - tmpMemory);
a[i] = int(lower_bound(tmpMemory, tmpMemory + count, a[i]) - tmpMemory);
if (maxR < L[i])maxR = L[i];
if (maxR < R[i])maxR = R[i];
if (maxR < a[i])maxR = a[i];
}
int source = maxn*coe - 1;
int sink = maxn*coe - 2;
int lastRoot = 0, newRoot = 0;
for (int i = 0;i < n;i++, newRoot = 0)
{
addEdge(source, i, b[i]);
addEdge(i, sink, w[i]);
addEdge(i, i + n, p[i]);
link_Tree_Edge(lastRoot, i + n, L[i], R[i], 0, maxR);
addTree(a[i], 0, maxR, lastRoot, newRoot, i, 0);
lastRoot = newRoot;
}
int debug;
printf("%lld\n", total - (long long)(debug = maxFlow2(source, sink)));
#ifdef _DEBUG
printf("%d\n", debug);
#endif // _DEBUG
}
int dst[maxn*coe], que[maxn*coe];
int dvis[maxn*coe];
int bfs_cnt = 1;
inline void addflow(int k, int flow) { EdgeNode[k].f += flow; EdgeNode[k ^ 1].f -= flow; }
//578110485
//532140314
int DFS(int source, int flow, int sink, int d = 0)
{
if (source == sink)return flow;
if (dst[sink] == d)return 0;
int sd = dst[source], fast = -1;
for (int i = Head[source];i > -1;i = EdgeNode[i].nxt)
{
edge_node &e = EdgeNode[i];
if (e.f == 0)continue;
if (dst[e.to] < sd + 1 || dvis[e.to] != bfs_cnt)
{
fast = i;
continue;
}
int f = DFS(e.to, e.f > flow ? flow : e.f, sink, d + 1);
if (f)
{
e.f -= f;
if (e.f == 0)
{
if (fast == -1)
Head[source] = e.nxt;
else
EdgeNode[fast].nxt = e.nxt;
}
if (EdgeNode[i ^ 1].f == 0)
{
EdgeNode[i ^ 1].nxt = Head[e.to];
Head[e.to] = i ^ 1;
}
EdgeNode[i ^ 1].f += f;
return f;
}
fast = i;
}
return 0;
}
#ifdef _DEBUG
int pro_index[maxn*coe];
#endif // _DEBUG
void BFS(int source, int sink)
{
int size = deep + n2 + 10;
int size_que = maxn*coe;
/*memset(dst, 0x3f, size * sizeof(int));*/
dst[source] = 0;
dst[sink] = INF;
dvis[source] = bfs_cnt;
int l = 0, r = 1;
que[0] = source;
int disSink = 0;
#ifdef _DEBUG
pro_index[source] = -1;
#endif // _DEBUG
while (l != r)
{
int v = que[l++];
if (l == size)l = 0;
for (int i = Head[v];i > -1;i = EdgeNode[i].nxt)
{
edge_node &e = EdgeNode[i];
if (e.f == 0)continue;
if (dvis[e.to] == bfs_cnt)
{
//if (e.to == sink&&dst[e.to] > disSink)disSink = dst[e.to];
continue;
}
dst[e.to] = dst[v] + 1;
dvis[e.to] = bfs_cnt;
que[r++] = e.to;
if (r == size)r = 0;
}
}
//if (disSink&&disSink != dst[sink])dst[sink] = (dst[sink] + disSink) / 2;
}
void BFS_2(int s)
{
dst[s] = 0;
int l = 0, r = 1;
int siz = maxn*coe;
que[0] = s;
while (l < r)
{
int v = que[l++];
if (l == siz)l = siz;
for (int i = Head[v];i > -1;i = EdgeNode[i].nxt)
{
edge_node &e = EdgeNode[i];
if (e.f)continue;
if (dst[e.to] != INF)continue;
dst[e.to] = dst[v] + 1;
que[r++] = e.to;
if (r == siz)r = siz;
}
}
#if 1
for (int k = 0;k < siz;k++)
{
for (int i = Head[k];i > -1;i = EdgeNode[i].nxt)
{
edge_node &e = EdgeNode[i];
if (e.f)continue;
reduce(k, e);
}
}
#endif
}
int pro[maxn*coe];
int cur[maxn*coe];
int cnt[maxn*coe];
int maxFlow2(int source, int sink)
{
memset(dst, 0x3F, sizeof dst);
memset(cnt, 0, sizeof cnt);
memcpy(cur, Head, maxn*coe * sizeof(int));
dst[sink] = 0;
int size = deep + n2 + 2;
BFS_2(sink);
for (int i = 0;i < maxn*coe;i++)if (dst[i] != INF)cnt[dst[i]]++;
int flow = 0;
int now = source;
pro[now] = now;
while (dst[source] < size)
{
int m = size - 1, flag = 1;
if(now ==sink)
{
int f = EdgeNode[cur[source]].f, index = source, up = 1;
for (int i = pro[now];i != source;i = pro[i])
{
edge_node &e = EdgeNode[cur[i]];
if (e.f > f)continue;
f = e.f;
index = i;
}
if (f == EdgeNode[cur[source]].f)index = source;
for (int i = pro[sink];;i = pro[i])
{
edge_node &e = EdgeNode[cur[i]];
e.f -= f;
if (e.f == 0)reduce(i, e);
if (EdgeNode[cur[i] ^ 1].f == 0)
{
int v = cur[i] ^ 1;
EdgeNode[v].nxt = Head[e.to];
if (Head[e.to] > -1)
EdgeNode[Head[e.to]].fir = v;
EdgeNode[v].fir = -1;
Head[e.to] = v;
}
EdgeNode[cur[i] ^ 1].f += f;
if (up)cur[i] = Head[i];
if (i == index)up = 0;
if (i == source)break;
}
now = pro[index];
flow += f;
}
for (int i = cur[now];i > -1;i = EdgeNode[i].nxt)
{
edge_node &e = EdgeNode[i];
if (e.f == 0)continue;
if (dst[e.to] + 1 != dst[now])continue;
cur[now] = i;
pro[e.to] = now;
now = e.to;
flag = 0;
break;
}
if (flag)
{
cur[now] = Head[now];
for (int i = cur[now];i > -1;i = EdgeNode[i].nxt)
{
edge_node &e = EdgeNode[i];
if (e.f == 0)continue;
if (dst[e.to] < m)m = dst[e.to];
}
--cnt[dst[now]];
if (cnt[dst[now]] == 0)break;
dst[now] = m + 1;
cnt[dst[now]]++;
now = pro[now];
}
}
return flow;
}
int maxFlow(int source, int sink)
{
int ret = 0, f = 1;
double B = 0, D = 0;
clock_t a, b, c;
int dfs_cnt = 0;
while (1)
{
a = clock();
BFS(source, sink);
b = clock() - a;
B += double(b) / 1000;
if (dvis[sink] != bfs_cnt)break;
f = 1;
a = clock();
while (f)
{
ret += (f = DFS(source, INF, sink));
++dfs_cnt;
}
b = clock() - a;
D += double(b) / 1000;
++bfs_cnt;
}
printf("D :%f\n B :%f\n bfs_cnt %d\n dfs_cnt %d\n", D, B, bfs_cnt, dfs_cnt);
return ret;
}
/*
20
9 11 25 20 29 15
13 16 27 2 37 9
39 8 1 5 36 25
13 38 9 29 35 1
25 16 22 3 21 27
28 9 33 1 26 29
18 33 23 25 31 2
1 9 25 3 21 39
11 1 31 23 25 19
26 1 23 1 6 26
2 17 18 3 25 4
6 1 11 11 38 22
19 5 17 1 22 1
22 26 13 18 21 27
35 22 25 1 23 13
1 4 13 7 21 21
13 9 6 7 33 29
19 11 1 16 30 1
28 3 27 6 28 23
21 39 7 21 33 39
403
5
0 3 1 0 0 3
1 3 2 0 1 3
2 6 10 0 2 3
3 5 0 0 3 3
3 5 2 0 4 2
5
0 2 7 0 0 1
0 5 2 0 1 5
2 2 2 0 3 1
2 3 2 0 3 1
2 5 2 0 4 1
*/