ARC122F Domination

ARC122F Domination

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

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

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

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

fi=min⁡j=1i(fj−1+min⁡l=1m(max⁡(rxi−bxl,0)+max⁡(ryj−byl,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),类似最短路松弛,考虑建模优化。

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

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

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

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

min⁡1≤l≤m(max⁡(rxi−bxl,0)+max⁡(ryj−byl,0))\min_{1\le l\le m}(\max(rx_{i}-bx_{l},0)+\max(ry_{j}-by_{l},0))

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

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

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

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

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

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

只做 kk 次 dij 增广,时间复杂度 O(knlog⁡n)\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  阅读(44)  评论(0)    收藏  举报  来源