[CF587D] Duff in Mafia

前言

加油啊,不然屯的炉石英文台词在退役前用不完了!

题目

洛谷

CF

讲解

让最大值最小,条件反射直接二分。

随便画画图发现一个点如果有超过两条相同颜色的边就会寄,如果一个点超过两组颜色相同的边也会寄。

剩下的情况就很 2-SAT 了。

如果有且仅有两条颜色相同的边,显然二者必选其一,而其它边不能选。

如果没有,意思是这个点我们能选且仅能选一条边,也就是说我们需要在 2-SAT 的图上每条边选的状态需要连向其它所有边不选的状态,这个可以前缀和优化建图实现。

外面套个二分就做完了,时间复杂度 \(O(n\log_2c)\)

代码

懒得算空间就随便开了。
//12252024832524
#include <bits/stdc++.h>
#define TT template<typename T>
using namespace std; 

typedef long long LL;
const int MAXN = 50005 << 3;
int n,m,cnt;

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 head[MAXN],tot,lst;
struct edge{
	int v,nxt;
}e[MAXN<<2];
void Add_Edge(int u,int v){
//	printf("ad %d %d\n",u,v);
	e[++tot] = edge{v,head[u]};
	head[u] = tot;
}

int value[MAXN];
struct Edge{
	int clr,val,ID;
	bool operator < (const Edge &px)const{
		return clr < px.clr;
	}
};
vector<Edge> G[MAXN];

int inv(int x){return x <= m ? x+m : x-m;}
int dfn[MAXN],dfntot,low[MAXN],bl[MAXN],qlt,s[MAXN],tl;
bool ins[MAXN];
void dfs(int x){
	s[++tl] = x; ins[x] = 1;
	dfn[x] = low[x] = ++dfntot;
	for(int i = head[x],v; i ;i = e[i].nxt){
		if(!dfn[v = e[i].v]) dfs(v),low[x] = Min(low[x],low[v]);
		else if(ins[v]) low[x] = Min(low[x],dfn[v]);
	}
	if(low[x] == dfn[x]){
		++qlt; int v;
		do{
			ins[v = s[tl--]] = 0;
			bl[v] = qlt;
		}while(v ^ x);
	}
}
bool check(int up){
	tot = lst;
	for(int i = 1;i <= cnt;++ i) while(head[i] > lst) head[i] = e[head[i]].nxt;
	for(int i = 1;i <= m;++ i) if(value[i] > up) Add_Edge(i,inv(i));
	for(int i = 1;i <= cnt;++ i) dfn[i] = 0; dfntot = tl = qlt = 0;
	for(int i = 1;i <= cnt;++ i) if(!dfn[i]) dfs(i);
	for(int i = 1;i <= m;++ i) if(bl[i] == bl[i+m]) return 0;
	return 1;
}

int main()
{
//	freopen(".in","r",stdin);
//	freopen(".out","w",stdout);
	n = Read(); m = Read(); cnt = m<<1;
	for(int i = 1,u,v,clr,val;i <= m;++ i){
		u = Read(); v = Read();
		clr = Read(); value[i] = val = Read();
		G[u].emplace_back(Edge{clr,val,i});
		G[v].emplace_back(Edge{clr,val,i});
	}
	for(int i = 1;i <= n;++ i) sort(G[i].begin(),G[i].end());
	for(int i = 1;i <= n;++ i){
		int ID = -1;
		for(int l = 0,r,len = G[i].size();l < len;l = r+1){
			r = l;
			while(r+1 < len && G[i][r+1].clr == G[i][l].clr) ++r;
			if(r-l+1 >= 3) {printf("No\n");return 0;}
			else if(r-l+1 == 2){
				if(ID >= 0) {printf("No\n");return 0;}
				ID = l;
			}
		}
		if(ID >= 0){
			Add_Edge(G[i][ID].ID,inv(G[i][ID+1].ID));
			Add_Edge(inv(G[i][ID].ID),G[i][ID+1].ID);
			Add_Edge(G[i][ID+1].ID,inv(G[i][ID].ID));
			Add_Edge(inv(G[i][ID+1].ID),G[i][ID].ID);
			for(int j = 0,len = G[i].size();j < len;++ j)
				if(j != ID && j != ID+1) Add_Edge(G[i][j].ID,inv(G[i][j].ID));
		}
		else{
			int len = G[i].size();
			for(int j = 0;j < len;++ j){
				if(j) Add_Edge(G[i][j].ID,lst);
				lst = ++cnt; Add_Edge(lst,inv(G[i][j].ID));
				if(j) Add_Edge(lst,lst-1);
			}
			for(int j = --len;j >= 0;-- j){
				if(j < len) Add_Edge(G[i][j].ID,lst);
				lst = ++cnt; Add_Edge(lst,inv(G[i][j].ID));
				if(j < len) Add_Edge(lst,lst-1);
			}
		}
	}
	lst = tot;
	if(!check(1e9)) {printf("No\n");return 0;}
	int l = 0,r = 1e9,ans = 1e9;
	while(l <= r){
		int mid = (l+r) >> 1;
		if(check(mid)) r = mid-1,ans = mid;
		else l = mid+1;
	}
	check(ans);
	printf("Yes\n");
	Put(ans,' '); ans = 0;
	for(int i = 1;i <= m;++ i) if(bl[i] < bl[i+m]) ++ans;
	Put(ans,'\n');
	for(int i = 1;i <= m;++ i) if(bl[i] < bl[i+m]) Put(i,' ');
	return 0;
}
posted @ 2022-03-06 21:26  皮皮刘  阅读(28)  评论(0编辑  收藏  举报