[20220315联考] 等你哈苏德

前言

这场考试第一感觉都挺准的,但是就是不会做。

题目

没有链接

给整数 \(n,m\)\(m\) 条线段,一些线段已经被黑白染色,一些待定,你需要给线段染色以保证每个点被黑线段和白线段覆盖条数的差值的绝对值小于等于 1,无解输出 -1。

\(1\le l_i\le r_i\le n\le 10^9;1\le m\le 3\times 10^4;-1\le w_i\le 1.\)

样例输入1
4 1000000000
1 9 -1
2 6 -1
1 8 -1
1 7 -1
样例输出1
1 1 0 0

讲解

我上来就想混合图欧拉路,但是不会转化,于是就寄了。

但其实正解就是这个,考虑混合图欧拉通路的做法是对奇度数的点连边之后转欧拉回路做法,网络流用于反悔边的方向,而这道题的奇度数显然就是 \(-1\)\(+1\),尽管我们并不知道应该是正还是负。

所以我们离散化后先求出度数(显然本题中就是被线段覆盖的个数),对于有向边(本题中就是已经定了颜色的边),无法反悔,而对于无向边(没定颜色的边)随便定一个方向,在网络流中连边表示可以反悔。

而对于最后奇度数的点,我们将它们依次两两连无向边(第一个连第二个,第三个连第四个,...)

然后直接 \(\tt Dinic\) 即可,混合图欧拉路部分见上面给出的网址。

代码

//12252024832524
#include <bits/stdc++.h>
#define TT template<typename T>
using namespace std; 

typedef long long LL;
const int MAXN = 60005;
const int INF = 0x3f3f3f3f;
int n,m;

LL Read()
{
	LL x = 0,f = 1;char c = getchar();
	while(c > '9' || c < '0'){if(c == '-')f = -1;c = getchar();}
	while(c >= '0' && c <= '9'){x = (x*10) + (c^48);c = getchar();}
	return x * f;
}
TT void Put1(T x)
{
	if(x > 9) Put1(x/10);
	putchar(x%10^48);
}
TT void Put(T x,char c = -1)
{
	if(x < 0) putchar('-'),x = -x;
	Put1(x); if(c >= 0) putchar(c);
}
TT T Max(T x,T y){return x > y ? x : y;}
TT T Min(T x,T y){return x < y ? x : y;}
TT T Abs(T x){return x < 0 ? -x : x;}

int l[MAXN],r[MAXN],clr[MAXN],p[MAXN],in[MAXN],pre[MAXN],idid[MAXN];
int head[MAXN],tot = 1,cur[MAXN];
struct edge{
	int v,w,nxt;
}e[MAXN<<2];
void Add_Edge(int u,int v,int w){
	e[++tot] = edge{v,w,head[u]};
	head[u] = tot;
}
void Add_Double_Edge(int u,int v,int w){
	Add_Edge(u,v,w);
	Add_Edge(v,u,0);
}

int dis[MAXN];
bool bfs(int S,int T){
	for(int i = 1;i <= T;++ i) dis[i] = INF;
	queue<int> q; q.push(S); dis[S] = 0;
	while(!q.empty()){
		int x = q.front(); q.pop();
		for(int i = head[x],v; i ;i = e[i].nxt)
			if(e[i].w && dis[x] + 1 < dis[v = e[i].v])
				dis[v] = dis[x]+1,q.push(v);
	}
	return dis[T] < INF;
}
int dfs(int x,int flow,int T){
	if(x == T) return flow;
	int ret = 0;
	for(int &i = cur[x],v; i ;i = e[i].nxt)
		if(e[i].w && dis[x] + 1 == dis[v = e[i].v]){
			int dz = dfs(v,Min(e[i].w,flow-ret),T);
			e[i].w -= dz; e[i^1].w += dz;
			if((ret += dz) == flow) break;
		}
	return ret;
}
int dinic(int S,int T){
	int ret = 0;
	while(bfs(S,T)){
		for(int i = 1;i <= T;++ i) cur[i] = head[i];
		ret += dfs(S,INF,T);
	}
	return ret;
}

int main()
{
//	freopen("wait.in","r",stdin);
//	freopen("wait.out","w",stdout);
	m = Read(); n = Read();
	for(int i = 1;i <= m;++ i)
		p[(i<<1)-1] = l[i] = Read(),p[i << 1] = r[i] = Read()+1,clr[i] = Read();
	sort(p+1,p+(m<<1)+1);
	n = unique(p+1,p+(m<<1)+1)-p-1;
	for(int i = 1;i <= m;++ i){
		l[i] = lower_bound(p+1,p+n+1,l[i])-p;
		r[i] = lower_bound(p+1,p+n+1,r[i])-p;
		++pre[l[i]]; --pre[r[i]];
		if(!clr[i]){//white
			--in[r[i]],++in[l[i]];
		}
		else if(clr[i] == 1){//black
			++in[r[i]],--in[l[i]];
		}
		else{//tbd
			++in[r[i]],--in[l[i]]; idid[i] = tot+1;
			Add_Double_Edge(r[i],l[i],1);
		}
	}
	int S = n+1,T = n+2,nd = 0;
	for(int i = 1;i <= n;++ i) 
		if((pre[i] += pre[i-1]) & 1)
			--in[i],++in[i+1],Add_Double_Edge(i+1,i,1);
	for(int i = 1;i <= n;++ i){
		if(in[i] > 0) Add_Double_Edge(S,i,in[i]>>1),nd += in[i]>>1;
		else if(in[i] < 0) Add_Double_Edge(i,T,(-in[i])>>1);
	}
	if(dinic(S,T) < nd) {Put(-1,'\n');return 0;}
	for(int i = 1;i <= m;++ i)
		if(idid[i]){
			if(e[idid[i]].w) Put(1,' ');
			else Put(0,' ');
		}
		else Put(clr[i],' ');
	return 0;
}
posted @ 2022-03-15 16:43  皮皮刘  阅读(62)  评论(0编辑  收藏  举报