JZOJ 6231 【NOI2019模擬2019.6.25】等你哈蘇德(歐拉回路,最大流)

Description


Joker 有一些黑. 白. 區. 間. [li; ri],有些區間已經被指定了顏色,有些卻沒有。你要指定
這些未染色區間的顏色,使得數軸上對於每個點,覆蓋他的黑區間個數和白區間個數差
的絕對值小. 於. 等. 於. 1

1<=m<=3e4

題解:


首先這一類問題可以往網絡流啊歐拉回路這一類圖論算法上靠。

假設把每一個點看成一個小段,即把區間[l,r]變成[l,r+1],使l->r+1連邊,如果所有點的度數都是偶數,找若干條歐拉回路來給邊定向,這個時候對每一段來看,由於是迴路,走到另外一邊一定會走回來,所以黑區間-白區間=0

那麼如果有度數奇數的點怎麼辦呢?
不妨在這些奇點中加輔助邊,不妨從左往右掃,當前的點是奇點,就和下一個點連邊(不是下一個奇點)。

由於一個段這樣最多被一條輔助邊覆蓋,所以就是abs<=1的。

然後考慮有一些邊被定向了怎麼辦。

對沒有定向的邊也定個向,那麼這些邊可以反向。

對每一點求出入度-出度。

負數就放二分圖的左邊,正數就放二分圖的右邊,流量是abs,如果有一個邊x->y可以反向,那麼就連這條邊,流過這條邊的意義就顯然了。

注意還是要加輔助邊(可反)。

有解條件滿流,一條邊被流過表示反向。

Code:

#include<bits/stdc++.h>
#define fo(i, x, y) for(int i = x, B = y; i <= B; i ++)
#define ff(i, x, y) for(int i = x, B = y; i <  B; i ++)
#define fd(i, x, y) for(int i = x, B = y; i >= B; i --)
#define ll long long
#define pp printf
#define hh pp("\n")
using namespace std;

const int N = 1e5 + 5;
map<int, int> bz;

int n, m, d[N], d0;
int l[N], r[N], w[N], b[N];
int fi[N], nt[N * 10], to[N * 10], v[N * 10], tot = 1;

void link(int x, int y, int z) {
	nt[++ tot] = fi[x], to[tot] = y, v[tot] = z, fi[x] = tot;
	nt[++ tot] = fi[y], to[tot] = x, v[tot] = 0, fi[y] = tot;
}
int S, T, co[N], cc[N], cur[N];

int dg(int x, int flow) {
	if(x == T) return flow;
	int use = 0;
	for(int i = cur[x]; i; cur[x] = i = nt[i])
		if(cc[x] == cc[to[i]] + 1 && v[i]) {
			int t = dg(to[i], min(flow - use, v[i]));
			v[i] -= t; v[i ^ 1] += t; use += t;
			if(flow == use) return use;
		}
	cur[x] = fi[x];
	if(!(-- co[cc[x]])) cc[S] = T;
	++ co[++ cc[x]];
	return use;
}

int main() {
	freopen("wait.in", "r", stdin);
	freopen("wait.out", "w", stdout);
	scanf("%d %d", &n, &m);
	fo(i, 1, n) {
		scanf("%d %d %d", &l[i], &r[i], &w[i]);
		r[i] ++;
		d[++ d0] = l[i]; d[++ d0] = r[i];
	}
	sort(d + 1, d + d0 + 1);
	d0 = unique(d + 1, d + d0 + 1) - (d + 1);
	fo(i, 1, d0) bz[d[i]] = i;
	fo(i, 1, d0) d[i] = 0;
	S = d0 + 1, T = S + 1;
	fo(i, 1, n) {
		l[i] = bz[l[i]];
		r[i] = bz[r[i]];
		if(w[i] == -1) {
			d[l[i]] --; d[r[i]] ++;
			link(l[i], r[i], 2);
			b[i] = tot;
		} else
		if(w[i] == 0) d[l[i]] --, d[r[i]] ++; else
		d[l[i]] ++, d[r[i]] --;
	}
	fo(i, 1, d0) if(d[i] & 1) {
		d[i] --;
		d[i + 1] ++;
		link(i, i + 1, 2);
	}
	int ans = 0;
	fo(i, 1, d0) if(d[i] <= 0)
		link(S, i, -d[i]); else
		link(i, T, d[i]), ans += d[i];
	co[0] = T;
	for(; cc[S] < T; ) ans -= dg(S, 1 << 30);
	if(!ans) {
		fo(i, 1, n) {
			if(w[i] != -1) pp("%d ", w[i]); else
			pp("%d ", v[b[i]] == 2);
		}
	} else {
		pp("-1\n");
	}
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章