题目链接:BZOJ3218
题目大意:
这道题的题面和题目没有任何关系。以及,题目大意略。
分析
1. 显然这道题是一个最大流最小割模型。
2. 设S割的点为黑格,T割的点为白格;对于每个点 i ,由S向 i 点连边,容量为 bi ;由 i 向T连边,容量为 wi ;表示使 i 属于S割会损失 i 作为白格子的优美度;使 i 属于T割会损失 i 作为黑格子的优美度;
3. 由 i 向 i′ 连边,容量为 pi ;由可以使 i 变得奇♂怪的 j 向 i′ 连边,容量为 INF ;表示若 i 属于S割且 j 属于T割,那么就会损失 pi 的优美度。
4. 然后最大流最小割跑一遍,用 ∑(bi+wi)−maxflow 即为答案;但是边太多 (N2) ,会超时。
5. 对于每个点,将它以 ai 为权值,对应到权值线段树上;那么对于 i′ ,只需要对由 [1..i−1] 的点集构成的权值线段树中的区间 [li...ri] 连边就好了,而线段树上的点之间相互连边,叶子节点向其对应的点连边,容量均 INF ,但是这样有 N 棵线段树,边的数量还是 N2 。
6. 这样的话,可以用主席树来减少线段树的点的数量,边的数量就变成 NlogN 了。
上代码
#include
#include
#include
#include
#include
using namespace std;
const int N = 5e3 + 10;
const int M = 4e5 + 10;
const int INF = 0x3f3f3f3f;
int n;
inline int read() {
char ch;
int ans = 0, neg = 1;
while (!isdigit(ch = getchar()))
if (ch == '-') neg = -1;
while (isdigit(ch))
ans = ans * 10 + ch - '0', ch = getchar();
return ans * neg;
}
int SS, TT, cnt;
int head[M], len;
#define id(a) ((a) + 2)
struct Lib {
int st, to, nxt, flow;
inline void add(int a, int b, int c) {
st = a, to = b, flow = c;
nxt = head[a], head[a] = len++;
}
} lib[M << 1];
inline void makePath(int a, int b, int c) {
lib[len].add(a, b, c), lib[len].add(b, a, 0);
}
queue <int> Q;
int dep[M], num[M], pre[M], curHead[M];
void bfs() {
memset(dep, 0x3f, sizeof(dep));
dep[TT] = 0, Q.push(TT);
while (!Q.empty()) {
int tmp = Q.front(); Q.pop();
for (int p = head[tmp]; p; p = lib[p].nxt) {
int now = lib[p].to;
if (!lib[p ^ 1].flow || dep[now] != INF) continue;
dep[now] = dep[tmp] + 1, Q.push(now);
}
}
}
int augment() {
int tmp = TT, minn = INF;
while (tmp != SS) {
minn = min(minn, lib[pre[tmp]].flow);
tmp = lib[pre[tmp]].st;
} tmp = TT;
while (tmp != SS) {
lib[pre[tmp]].flow -= minn, lib[pre[tmp] ^ 1].flow += minn;
tmp = lib[pre[tmp]].st;
}
return minn;
}
int ISAP() {
bfs();
for (int i = 1; i <= cnt; i++) {
curHead[i] = head[i];
if (dep[i] != INF) num[dep[i]]++;
}
int ans = 0, tmp = SS;
while (dep[SS] < INF) {
if (tmp == TT) ans += augment(), tmp = SS;
bool flag = false;
for (int &p = curHead[tmp]; p; p = lib[p].nxt) {
int now = lib[p].to;
if (lib[p].flow && dep[now] == dep[tmp] - 1) {
pre[now] = p, tmp = now, flag = true; break;
}
}
if (!flag) {
int minn = INF;
if (!--num[dep[tmp]]) break;
for (int p = head[tmp]; p; p = lib[p].nxt)
if (lib[p].flow) minn = min(minn, dep[lib[p].to]);
if (minn < INF) num[dep[tmp] = minn + 1]++;
curHead[tmp] = head[tmp];
if (tmp != SS) tmp = lib[pre[tmp]].st;
}
}
return ans;
}
int T[N], lc[M], rc[M];
inline int modify(int a, int p, int poi) {
int now = ++cnt, tmp = now;
int l = 1, r = n, mid;
while (l < r) {
mid = (l + r) >> 1;
if (p <= mid) {
makePath(now, rc[now] = rc[a], INF);
makePath(now, lc[now] = ++cnt, INF);
now = lc[now], a = lc[a], r = mid;
} else {
makePath(now, lc[now] = lc[a], INF);
makePath(now, rc[now] = ++cnt, INF);
now = rc[now], a = rc[a], l = mid + 1;
}
}
makePath(now, id(poi), INF), makePath(now, a, INF);
return tmp;
}
void calcPath(int a, int l, int r, int ll, int rr) {
if (!a || ll > rr) return;
if (l == ll && r == rr) return makePath(cnt, a, INF);
int mid = (l + r) >> 1;
if (rr <= mid) return calcPath(lc[a], l, mid, ll, rr);
else if (ll > mid) return calcPath(rc[a], mid + 1, r, ll, rr);
calcPath(lc[a], l, mid, ll, mid), calcPath(rc[a], mid + 1, r, mid + 1, rr);
}
int dsc[N];
struct Blc {
int a, l, r, b, w, p;
inline void input() {
a = read(), b = read(), w = read();
l = read(), r = read(), p = read();
}
} blc[N];
void calcDsc() {
for (int i = 1; i <= n; i++)
blc[i].input(), dsc[i] = blc[i].a;
sort(dsc + 1, dsc + n + 1);
for (int i = 1; i <= n; i++) {
blc[i].a = lower_bound(dsc + 1, dsc + n + 1, blc[i].a) - dsc;
blc[i].l = lower_bound(dsc + 1, dsc + n + 1, blc[i].l) - dsc;
blc[i].r = upper_bound(dsc + 1, dsc + n + 1, blc[i].r) - dsc - 1;
}
}
void init() {
n = read(), calcDsc();
SS = 1, TT = 2, len = 2, cnt = id(n);
for (int i = 1; i <= n; i++)
makePath(SS, id(i), blc[i].b), makePath(id(i), TT, blc[i].w);
for (int i = 1; i <= n; i++) {
makePath(id(i), ++cnt, blc[i].p);
calcPath(T[i - 1], 1, n, blc[i].l, blc[i].r);
T[i] = modify(T[i - 1], blc[i].a, i);
}
}
int figure() {
int ans = 0;
for (int i = 1; i <= n; i++)
ans += blc[i].b + blc[i].w;
return ans -= ISAP(), ans;
}
int main() {
init();
printf("%d\n", figure());
return 0;
}
以上