题解 [ARC122F] Domination

传送门

一个破题做一下午加一晚上跟颓废有什么区别

首先发现只有单调栈中的红色石头是有用的
然后发现操作等价于移动蓝色石头覆盖其左下的红色石头
发现每个红色石头都要被覆盖 \(\geqslant k\)
然后发现覆盖之间是独立的
那么可以拆分成 \(k\)\(k=1\) 的方案
考虑 \(k=1\) 怎么做
发现现在是区间覆盖,可以转化成路径问题
用石头 \(i\) 覆盖 \([l, r]\) 等价于一条 \(l\to i\to r\) 的路径
这样边数很大
一个 trick 是利用坐标轴
将贡献拆成 \(\max(y_l-y_i, 0)+\max(x_r-x_i, 0)\)
那么在 \(x\) 轴正方向走一步代价为 1,反方向走一步代价为 0
\(y\) 轴向下走一步代价为 1,向上走一步代价为 0
一个蓝色石头可以无代价从 \(y_i\) 跳到 \(x_i\)
为了让路径经过坐标轴,从红色石头向 \(y_i\) 连边,从 \(x_i\) 向下一个红色石头连边
于是可以用最短路求 \(k=1\) 的答案了
然后 \(k>1\),发现每个蓝色石头只能用一次,就变成了费用流
然而 EK 是可以卡的,需要 zkw 费用流

  • 原始边权均非负的费用流图是没有负环的
    从 rvalue 学姐博里粘个证明:

    Q: 你这个费用流里既然会冒出负权来, 那要是推反向边的时候在残量网络里増广出负环了怎么破?
    A: EK费用流的过程每次只増广最短路, 所以任意时刻増广出来的流一定都是最小费用流. 但是如果残量网络中存在负环, 那么我们显然可以让一部分流量改道流经这个负环来让费用减少, 这样就矛盾了. 所以一定不会増广出负环.

  • 注意 zkw/原始对偶 若使用 \(\tt spfa\) 预处理 \(h\) 的话复杂度仍是 \(O(nmf)\)
    所以若图中没有负环就不要跑这个预处理了

于是复杂度 \(O(kn\log n)\)\(n, m\) 同阶)

点击查看代码
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define N 3000010
#define fir first
#define sec second
#define ll long long
//#define int long long

char buf[1<<21], *p1=buf, *p2=buf;
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf, 1, 1<<21, stdin)), p1==p2?EOF:*p1++)
inline int read() {
	int ans=0, f=1; char c=getchar();
	while (!isdigit(c)) {if (c=='-') f=-f; c=getchar();}
	while (isdigit(c)) {ans=(ans<<3)+(ans<<1)+(c^48); c=getchar();}
	return ans*f;
}

int n, m, k;
#undef unix
bool vis[N];
ll dis[N], h[N], ans;
int head[N], back[N], inc[N], ecnt=1;
pair<int, int> sta[N], red[N], blue[N];
int unix[N], uniy[N], id[N], idx[N], idy[N], tot, s, t, xsiz, ysiz, top;
struct edge{int to, next, flw; ll cst;}e[N<<1];
inline void add(int s, int t, int f, ll c) {/* cout<<s<<' '<<t<<' '<<f<<' '<<c<<endl; */ e[++ecnt]={t, head[s], f, c}; head[s]=ecnt;}

void spfa(int s, int t) {
	memset(h, 0x3f, sizeof(h));
	queue<int> q;
	h[s]=0; q.push(s);
	while (q.size()) {
		int u=q.front(); q.pop();
		vis[u]=0;
		for (int i=head[u],v; ~i; i=e[i].next) {
			v = e[i].to;
			if (e[i].flw && h[u]+e[i].cst<h[v]) {
				h[v]=h[u]+e[i].cst;
				if (!vis[v]) q.push(v), vis[v]=1;
			}
		}
	}
}

bool dijkstra(int s, int t) {
	for (int i=1; i<=tot; ++i) dis[i]=0x3f3f3f3f3f3f3f3f, back[i]=-1, vis[i]=0;
	priority_queue<pair<ll, int>> q;
	q.push({dis[s]=0, s}); inc[s]=INF;
	while (q.size()) {
		int u=q.top().sec; q.pop();
		if (vis[u]) continue;
		for (int i=head[u],v; ~i; i=e[i].next) {
			v=e[i].to; ll val=e[i].cst+h[u]-h[v];
			if (e[i].flw && dis[u]+val<dis[v]) {
				dis[v]=dis[u]+val;
				back[v]=i; inc[v]=min(inc[u], e[i].flw);
				q.push({-dis[v], v});
			}
		}
	}
	return ~back[t];
}

// bool spfa(int s, int t) {
// 	memset(dis, 127, sizeof(dis));
// 	memset(back, -1, sizeof(back));
// 	dis[s]=0; inc[s]=INF;
// 	queue<int> q;
// 	q.push(s);
// 	int u;
// 	while (q.size()) {
// 		u=q.front(); q.pop();
// 		vis[u]=0;
// 		for (int i=head[u],v; ~i; i=e[i].next) {
// 			v = e[i].to;
// 			if (e[i].flw && dis[v]>dis[u]+e[i].cst) {
// 				dis[v]=dis[u]+e[i].cst;
// 				back[v]=i; inc[v]=min(inc[u], e[i].flw);
// 				if (!vis[v]) q.push(v), vis[v]=1;
// 			}
// 		}
// 	}
// 	return ~back[t];
// }

signed main()
{
	n=read(); m=read(); k=read();
	memset(head, -1, sizeof(head));
	for (int i=1; i<=n; ++i) red[i].fir=read(), red[i].sec=read();
	for (int i=1; i<=m; ++i) blue[i].fir=read(), blue[i].sec=read();
	sort(red+1, red+n+1);
	for (int i=1; i<=n; ++i) {
		while (top && sta[top].sec<=red[i].sec) --top;
		sta[++top]=red[i];
	}
	for (int i=1; i<=top; ++i) unix[++xsiz]=sta[i].fir, uniy[++ysiz]=sta[i].sec;
	for (int i=1; i<=m; ++i) unix[++xsiz]=blue[i].fir, uniy[++ysiz]=blue[i].sec;
	sort(unix+1, unix+xsiz+1);
	sort(uniy+1, uniy+ysiz+1);
	xsiz=unique(unix+1, unix+xsiz+1)-unix-1;
	ysiz=unique(uniy+1, uniy+ysiz+1)-uniy-1;
	for (int i=1; i<=top; ++i) sta[i]={lower_bound(unix+1, unix+xsiz+1, sta[i].fir)-unix, lower_bound(uniy+1, uniy+ysiz+1, sta[i].sec)-uniy};
	for (int i=1; i<=m; ++i) blue[i]={lower_bound(unix+1, unix+xsiz+1, blue[i].fir)-unix, lower_bound(uniy+1, uniy+ysiz+1, blue[i].sec)-uniy};
	// cout<<"siz: "<<xsiz<<' '<<ysiz<<endl;
	// cout<<"sta: "; for (int i=1; i<=top; ++i) cout<<"("<<sta[i].fir<<','<<sta[i].sec<<") "; cout<<endl;
	// cout<<"blue: "; for (int i=1; i<=m; ++i) cout<<"("<<blue[i].fir<<','<<blue[i].sec<<") "; cout<<endl;
	for (int i=1; i<=xsiz; ++i) idx[i]=++tot;
	for (int i=1; i<=ysiz; ++i) idy[i]=++tot;
	for (int i=1; i<=top+1; ++i) id[i]=++tot;
	for (int i=1; i<xsiz; ++i) add(idx[i], idx[i+1], INF, unix[i+1]-unix[i]), add(idx[i+1], idx[i], 0, unix[i]-unix[i+1]); //, cout<<unix[i+1]-unix[i]<<endl;
	for (int i=2; i<=xsiz; ++i) add(idx[i], idx[i-1], INF, 0), add(idx[i-1], idx[i], 0, 0);
	for (int i=2; i<=ysiz; ++i) add(idy[i], idy[i-1], INF, uniy[i]-uniy[i-1]), add(idy[i-1], idy[i], 0, uniy[i-1]-uniy[i]); //, cout<<uniy[i]-uniy[i-1]<<endl;
	for (int i=1; i<ysiz; ++i) add(idy[i], idy[i+1], INF, 0), add(idy[i+1], idy[i], 0, 0);
	for (int i=1; i<=top; ++i) {
		add(id[i], idy[sta[i].sec], k, 0), add(idy[sta[i].sec], id[i], 0, 0);
		add(idx[sta[i].fir], id[i+1], k, 0), add(id[i+1], idx[sta[i].fir], 0, 0);
	}
	for (int i=1; i<=m; ++i) add(idy[blue[i].sec], idx[blue[i].fir], 1, 0), add(idx[blue[i].fir], idy[blue[i].sec], 0, 0);
	s=id[1]; t=id[top+1];
	// spfa(s, t);
	int tem=0;
	while (dijkstra(s, t)) {
		for (int i=1; i<=tot; ++i) h[i]+=dis[i];
		tem+=inc[t];
		ans+=h[t]*inc[t];
		for (int u=t; u!=s; u=e[back[u]^1].to) {
			e[back[u]].flw-=inc[t];
			e[back[u]^1].flw+=inc[t];
		}
	}
	// while (spfa(s, t)) {
	// 	tem+=inc[t];
	// 	ans+=dis[t]*inc[t];
	// 	for (int u=t; u!=s; u=e[back[u]^1].to) {
	// 		e[back[u]].flw-=inc[t];
	// 		e[back[u]^1].flw+=inc[t];
	// 	}
	// }
	// assert(tem==k);
	printf("%lld\n", ans);
	// cout<<tot<<' '<<ecnt-1<<' '<<s<<' '<<t<<endl;

	return 0;
}
posted @ 2022-06-26 22:05  Administrator-09  阅读(3)  评论(0编辑  收藏  举报