P8465 「REOI-1」调整圣剑
题意
给定 \(n\) 个护符,每个护符有一个权值 \(a_i\),进行 \(k\) 次操作,每次选择一个护符,并获得护符的权值。
给定 \(q\) 个限制,表示在第 \(i\) 次调整必须调整前 \(x\) 个护符或在第 \(j\) 次调整时调整后 \(y\) 个护符。
求最小权值。
Sol
最小割板子题。
考虑建分层图,对于整张图分 \(k\) 层,每层 \(n + 1\) 个点。
两点之间连权值 \(a_i\) 即可。
考虑限制该怎么做,发现只需要在第 \(i\) 层向第 \(j\) 层连一条 \(inf\) 边就可以了。
因为这样如果 \(i\) 层选的点 \(\ge x\) 且 \(j\) 层选的点 \(\le y\),就会有一条 \(inf\) 的边需要割掉。
还有一个问题,就是每层可能会割 \(\ge 1\) 条边。
考虑对于每个点加上一个极大值,使得只要多割一条边,一定不优,这里取 \(1e11\)。
这样就做完了?
点数还是 \(n \times k\),无法通过。
考虑使用最大流的思路去思考这个模型。
注意到对于一条方向相同的链,直接取其中的最小值就可以了。
所以,我们把限制需要用到的点单独存下来,然后和前面的点的区间取个 \(min\),就行了。
\(RMQ\) 问题是 \(trivial\) 的。
对于每个限制,只会新增两个点,三条边。
点数与 \(n, q\) 同阶。
做完了。
Code
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <array>
#include <queue>
#include <cmath>
#include <bitset>
#define int long long
#define pii pair <int, int>
using namespace std;
#ifdef ONLINE_JUDGE
#define getchar() (p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 1 << 21, stdin), p1 == p2) ? EOF : *p1++)
char buf[1 << 23], *p1 = buf, *p2 = buf, ubuf[1 << 23], *u = ubuf;
#endif
int read() {
int p = 0, flg = 1;
char c = getchar();
while (c < '0' || c > '9') {
if (c == '-') flg = -1;
c = getchar();
}
while (c >= '0' && c <= '9') {
p = p * 10 + c - '0';
c = getchar();
}
return p * flg;
}
void write(int x) {
if (x < 0) {
x = -x;
putchar('-');
}
if (x > 9) {
write(x / 10);
}
putchar(x % 10 + '0');
}
#define fi first
#define se second
const int N = 1e6 + 5, M = 4e6 + 5, inf = 1e18;
namespace G {
array <int, N> fir;
array <int, M> nex, to, cap;
int cnt = 1;
void add(int x, int y, int z) {
cnt++;
nex[cnt] = fir[x];
to[cnt] = y;
cap[cnt] = z;
fir[x] = cnt;
}
void _add(int x, int y, int z) {
/* write(x), putchar(32); */
/* write(y), putchar(32); */
/* write(z), puts(""); */
add(x, y, z);
add(y, x, 0);
}
}
namespace Mfl {
array <int, N> dis, cur;
queue <int> q;
bool bfs(pii st) {
dis.fill(-1), dis[st.fi] = 0;
q.push(st.fi);
while (!q.empty()) {
int u = q.front();
q.pop();
for (int i = G::fir[u]; i; i = G::nex[i]) {
if (!G::cap[i] || ~dis[G::to[i]]) continue;
dis[G::to[i]] = dis[u] + 1, q.push(G::to[i]);
}
}
return ~dis[st.se];
}
int dfs(int x, int augcd, pii st) {
if (x == st.se) return augcd;
int augc = augcd;
for (int &i = cur[x]; i; i = G::nex[i]) {
if (!G::cap[i] || dis[G::to[i]] <= dis[x]) continue;
int flow = dfs(G::to[i], min(G::cap[i], augc), st);
augc -= flow;
G::cap[i] -= flow, G::cap[i ^ 1] += flow;
if (!augc) break;
}
return augcd - augc;
}
int dinic(pii st) {
int ans = 0;
while (bfs(st)) {
copy(G::fir.begin(), G::fir.end(), cur.begin());
ans += dfs(st.fi, inf, st);
}
return ans;
}
}
array <int, N> s;
namespace St {
array <array <int, 22>, N> sT;
array <int, N> lg;
void init(int n) {
for (int i = 1; i <= n; i++)
lg[i] = log2(i);
for (int i = 1; i <= n; i++)
sT[i].fill(inf);
for (int i = 1; i <= n; i++)
sT[i][0] = s[i];
for (int j = 1; j < 22; j++)
for (int i = 1; i + (1 << j) - 1 <= n; i++)
sT[i][j] = min(sT[i][j - 1], sT[i + (1 << (j - 1))][j - 1]);
}
int query(int l, int r) {
if (l > r) return inf;
int len = lg[r - l + 1];
return min(sT[l][len], sT[r - (1 << len) + 1][len]);
}
}
array <vector <pii>, N> cur;
array <pii, N> isl;
signed main() {
int n = read(), k = read(), q = read();
for (int i = 1; i <= n; i++)
s[i] = read();
St::init(n);
int cnt = 2 * k;
for (int i = 1; i <= q; i++) {
int l = read(), r = read(), x = read(), y = read();
if (x == n || y == n) continue;
cur[l].push_back(make_pair(x, i + q));
cur[r].push_back(make_pair(n - y, i));
}
for (int i = 1; i <= k; i++) {
sort(cur[i].begin(), cur[i].end());
int lst = i, res = 0;
/* write(cur[i].size()), puts("@"); */
for (int j = 0; j < (int)cur[i].size(); j++) {
cnt++;
/* write(cnt), puts("@"); */
G::_add(lst, cnt, St::query(res + 1, cur[i][j].fi) + 1e11);
int pos = cur[i][j].se > q ? cur[i][j].se - q : cur[i][j].se;
(cur[i][j].se > q ? isl[pos].fi : isl[pos].se) = cnt;
lst = cnt, res = cur[i][j].fi;
}
G::_add(lst, i + k, St::query(res + 1, n) + 1e11);
}
pii st(cnt + 1, cnt + 2);
for (int i = 1; i <= k; i++)
G::_add(st.fi, i, inf), G::_add(i + k, st.se, inf);
for (int i = 1; i <= q; i++)
G::_add(isl[i].fi, isl[i].se, inf);
write(Mfl::dinic(st) % (int)1e11), puts("");
return 0;
}