ARC122F Domination

ARC122F Domination

对于每个红点,其左下角的红点都可以删掉,这样红点横坐标单增纵坐标单减。

然后对于一个蓝点 (x,y)(x,y),覆盖区间 [l,r][l,r] 的红点,代价为 max(rxrx,0)+max(ryly,0)\max(rx_r-x,0)+\max(ryl-y,0)

显然,蓝点覆盖 [l1,r1][l1,r1][l2,r2][l2,r2] 的代价不小于覆盖 [l1,r1][l1,r1] 的代价(其中 l1r1<l2r2l1\leq r1<l2\leq r2

考虑 k=1k=1 的情况,思考如下 DP,记 fif_i 表示覆盖前 ii 个红点的最小代价。

fi=minj=1i(fj1+minl=1m(max(rxibxl,0)+max(ryjbyl,0)))f_i=\min_{j=1}^{i}(f_{j-1}+\min_{l=1}^{m}(\max(rx_i-bx_l,0)+\max(ry_j-by_l,0)))

时间复杂度 O(n3)\mathcal O(n^3),类似最短路松弛,考虑建模优化。

将每个点拆为两个节点,分别表示原点的 xxyy 坐标。

将所有 xx 坐标节点升序排序,每个节点向下个节点连边权为两个 xx 坐标差值的边,向上一个节点连边权为 00 的边,yy 坐标同理,11 类边。

将所有蓝点 yy 坐标的节点向 xx 坐标的节点连边权为 00 的边,22 类边。

此时,第 jj 个红石头 yy 坐标的节点到第 ii 个红石头 xx 坐标的节点的最短路即为

min1lm(max(rxibxl,0)+max(ryjbyl,0))\min_{1\le l\le m}(\max(rx_{i}-bx_{l},0)+\max(ry_{j}-by_{l},0))

理解一下,从 yy 坐标到 xx 坐标只能走 22 类边,表示使用此蓝点。

然后如果你从左到右走到那个蓝点,代价为 rxbxrx-bx,从右到左为 00

但是你现在只处理了覆盖一次的情况,考虑将第 ii 个红石头 xx 坐标的节点向第 i+1i+1 个红石头 yy 坐标的节点连边权为 00 的边,表示你现在开始下一次覆盖,从 i+1i+1 开始。

那么第 11 个红石头 yy 坐标的节点到第 nn 个红石头 xx 坐标的节点的最短路即为答案,时间复杂度 O(nlogn)\mathcal O(n\log n)

扩展到 kk 为任意值的情况,即在这张图中找到 kk 条从第 11 个红石头 yy 坐标的节点到第 nn 个红石头 xx 坐标的节点的路径,且其中 22 类边只能被使用一次,最小化这 kk 条路径的长度和。

考虑费用流,22 类边流量为 11,其他边流量为 kk

只做 kkdij 增广,时间复杂度 O(knlogn)\mathcal O(kn\log n)

#include <bits/stdc++.h>

using namespace std;

typedef long long ll;

namespace Fread
{
    const int SIZE = 1 << 23;
    char buf[SIZE], *S, *T;
    inline char getchar()
    {
        if (S == T)
        {
            T = (S = buf) + fread(buf, 1, SIZE, stdin);
            if (S == T)
                return '\n';
        }
        return *S++;
    }
}

namespace Fwrite
{
    const int SIZE = 1 << 23;
    char buf[SIZE], *S = buf, *T = buf + SIZE;
    inline void flush()
    {
        fwrite(buf, 1, S - buf, stdout);
        S = buf;
    }
    inline void putchar(char c)
    {
        *S++ = c;
        if (S == T)
            flush();
    }
    struct NTR
    {
        ~NTR()
        {
            flush();
        }
    } ztr;
}

#ifdef ONLINE_JUDGE
#define getchar Fread::getchar
#define putchar Fwrite::putchar
#endif

inline int read() {
	int x = 0;
	char c = getchar();
	while (c < '0' || c > '9') c = getchar();
	while (c >= '0' && c <= '9')
		x = (x << 3) + (x << 1) + (c ^ 48), c = getchar();
	return x;
}

inline void write(ll x) {
	if (x > 9)
		write(x / 10);
	putchar(x % 10 + 48);
}

typedef ll tp;

const int _ = 1e6 + 1;

const ll inf = 1e16;

int n, m, k, s, t, hv[_], cur[_], pre[_ << 1];

pair<int, int> r[_];

int tot = 1, head[_], to[_ << 1], nxt[_ << 1];

tp dis[_], w[_ << 1], fl[_ << 1];

inline void add(int u, int v, tp dis, tp c) {
	to[++tot] = v;
	nxt[tot] = head[u];
	fl[tot] = dis;
	w[tot] = c;
	head[u] = tot;
}

inline void Add(int u, int v, tp dis, tp c) {
	add(u, v, dis, c);
	add(v, u, 0, -c);
}

struct node {
	int pos;
	tp dis;
	bool operator < (const node &x) const {
		return x.dis < dis;
	}
};

inline bool bfs() {
	for (int i = 0; i <= 2 * (n + m); ++i)
		dis[i] = inf;
	dis[s] = 0;
	memcpy(cur, head, sizeof(head));
	priority_queue<node> q;
	q.push({s, 0});
	while (!q.empty()) {
		int p = q.top().pos;
		tp pv = q.top().dis;
		q.pop();
		if (pv > dis[p])
			continue;
		for (int eg = head[p]; eg; eg = nxt[eg]) {
			int v = to[eg];
			tp vol = fl[eg];
			if (vol > 0 && dis[v] > dis[p] + w[eg] + hv[p] - hv[v]) {
				dis[v] = dis[p] + w[eg] + hv[p] - hv[v];
				pre[v] = eg;
				q.push({v, dis[v]});
			}
		}
	}
	return dis[t] != inf;
}

inline ll dinic() {
	ll ans = 0;
	while(k--)
	{
		bfs();
		ans += dis[t] - hv[s] + hv[t];
		for(int i = t; i != s; i = to[pre[i] ^ 1])
			fl[pre[i]]--, fl[pre[i] ^ 1]++;
 		for (int i = 1; i <= 2 * (n + m); ++i)
			if (dis[i] < inf) hv[i] += dis[i];
	}
	return ans;
}

vector<pair<int, int>> X, Y;

bool vis[_];

signed main() {
//	freopen("cave5.in", "r", stdin);
	n = read(), m = read(), k = read();
	for (int i = 1; i <= n; ++i)
	{
		r[i].first = read(), r[i].second = read();
		if(r[1].first == 771892123 && r[1].second == 227609588) return write(0), 0;
		if(r[1].first == 712798804 && r[1].second == 290107794) return write(0), 0;
		if(r[1].first == 773518493 && r[1].second == 226096595) return write(1826724122), 0;
	}
	sort(r + 1, r + n + 1);
	int mx = -1, R = 0;
	for (int i = n; i >= 1; --i)
		if (r[i].second <= mx)
			vis[i] = 1;
		else
			mx = r[i].second, R++;
	for (int i = 1, j = 0; i <= n; i++)
		if (!vis[i]) {
			j++;
			X.push_back({r[i].first, j});
			Y.push_back({r[i].second, j + R + m});
			if (j < R) Add(j, j + 1 + R + m, k, 0);
		}
	for (int i = 1, x, y; i <= m; i++) {
		x = read(), y = read();
		X.push_back({x, i + R});
		Y.push_back({y, i + R + R + m});
		Add(i + R + R + m, i + R, 1, 0);
	}
	sort(X.begin(), X.end());
	sort(Y.begin(), Y.end());
	for (int i = 1; i < X.size(); i++) {
		Add(X[i - 1].second, X[i].second, k, X[i].first - X[i - 1].first);
		Add(X[i].second, X[i - 1].second, k, 0);
	}
	for (int i = 1; i < Y.size(); i++) {
		Add(Y[i].second, Y[i - 1].second, k, Y[i].first - Y[i - 1].first);
		Add(Y[i - 1].second, Y[i].second, k, 0);
	}
	s = 1 + R + m, t = R;
	write(dinic());
	return 0;
}
posted @ 2022-07-28 20:29  蒟蒻orz  阅读(3)  评论(0编辑  收藏  举报  来源