CF587D Duff in Mafia 题解

安利(:) 杂题选做

题目链接-Codeforces

首先忽略边权(,)考虑求一组可行的方案(.)可以使用(2-SAT)实现(,)建图需要前后缀优化(.)

加上边权的限制就是加一个二分(.)

强制让一个东西不能选就是加一条 ((x,1)->(x,0)) 的边(.)

(O(mlogm),)实现的时候注意节省空间(.)

我的代码是(|V|leq 7m,) (|E| leq 17m)


关于前后缀优化(:)

考虑我把原图中的点都拿出来并排成一排(p_1,p_2,..,p_m.)

然后我需要快速实现若干次一个点(u)往这一排点连边或者往这一排点中除了一个点的其他点连边(.)

那么(,)可以建出辅助点(pre_i)(suf_i,)分别表示连向(p_{1..i})和连向(p_{i..m})的点(.)

然后就可以连一个前缀(,)连一个后缀(,)就解决问题了(.)

一排点往点(u)连边的过程类似(.)

这个优化建图是线性的(.)


代码(:)

#include <bits/stdc++.h>
using namespace std;
template <typename T> void read(T &x){
	x = 0; int f = 1; char ch = getchar();
	while (!isdigit(ch)) {if (ch == '-') f = -1; ch = getchar();}
	while (isdigit(ch)) {x = x * 10 + ch - '0'; ch = getchar();}
	x *= f;
}
inline void write(int x){if (x > 9) write(x/10); putchar(x%10+'0'); }

const int N = 50005,M = 50005,V = N * 7,E = M * 17;

int cntv;
int He[V],Ne[E],To[E],_k;
inline void init(){ for (int i = 1; i <= cntv; ++i) He[i] = 0; _k = 0; }
inline void add(int x,int y){ ++_k; To[_k] = y,Ne[_k] = He[x],He[x] = _k; }

int Time,dfn[V],low[V],vis[V],stk[V],top,scc[V],scc_cnt;
inline void dfs(int x){
	dfn[x] = low[x] = ++Time; stk[++top] = x; vis[x] = 1;
	for (int y,p = He[x]; p ; p = Ne[p]){
		y = To[p];
		if (!dfn[y]) dfs(y),low[x] = min(low[x],low[y]);
		else if (vis[y]) low[x] = min(low[x],dfn[y]);
	}
	if (low[x] == dfn[x]){
		scc[x] = ++scc_cnt; vis[x] = 0;
		while (stk[top] ^ x) scc[stk[top]] = scc[x],vis[stk[top]] = 0,--top;
		--top;
	}
}
inline void tarjan(){
	int i;
	Time = 0,top = 0,scc_cnt = 0;
	for (i = 1; i <= cntv; ++i) dfn[i] = low[i] = vis[i] = scc[i] = stk[i] = 0;
	for (i = 1; i <= cntv; ++i) if (!dfn[i]) dfs(i);
}
int n,m,ex[M],ey[M],ec[M],et[M];

int eex[E],eey[E],le;

vector<int>G[N];
inline void build(int w){
	static int p[N],lenp,i,q[N],x,y;
	lenp = G[w].size();
	for (i = 1; i <= lenp; ++i) p[i] = G[w][i-1];
	for (i = 2; i <= lenp; ++i){ q[i] = ++cntv; ++le; eex[le] = q[i],eey[le] = p[i]; }
	for (i = 2; i < lenp; ++i){ ++le; eex[le] = q[i],eey[le] = q[i+1]; }
	for (i = 1; i < lenp; ++i){ ++le; eex[le] = p[i]+m,eey[le] = q[i+1]; }
	for (i = 1; i < lenp; ++i){ q[i] = ++cntv; ++le; eex[le] = q[i],eey[le] = p[i]; }
	for (i = 2; i < lenp; ++i){ ++le; eex[le] = q[i],eey[le] = q[i-1]; }
	for (i = 2; i <= lenp; ++i){ ++le; eex[le] = p[i]+m,eey[le] = q[i-1]; }
}
inline void work(){
	int i,x,y;
	map<pair<int,int> ,int>M; M.clear();
	cntv = m<<1;
	for (i = 1; i <= m; ++i){
		G[ex[i]].push_back(i),G[ey[i]].push_back(i);
		if (M.count(make_pair(ec[i],ex[i]))){
			x = M[make_pair(ec[i],ex[i])],y = i;
			++le; eex[le] = x,eey[le] = y+m;
			++le; eex[le] = x+m,eey[le] = y;
			++le; eex[le] = y,eey[le] = x+m;
			++le; eex[le] = y+m,eey[le] = x; 
		}
		else M[make_pair(ec[i],ex[i])] = i;
		
		if (M.count(make_pair(ec[i],ey[i]))){
			x = M[make_pair(ec[i],ey[i])],y = i;
			++le; eex[le] = x,eey[le] = y+m;
			++le; eex[le] = x+m,eey[le] = y;
			++le; eex[le] = y,eey[le] = x+m;
			++le; eex[le] = y+m,eey[le] = x; 
		}
		else M[make_pair(ec[i],ey[i])] = i;
	}
	for (i = 1; i <= n; ++i) if (G[i].size() > 1) build(i);
}

inline bool check(int v,int tp){
	int i;
	init();
	for (i = 1; i <= le; ++i) add(eex[i],eey[i]);
	for (i = 1; i <= m; ++i) if (et[i] > v) add(i+m,i);
	tarjan();
	for (i = 1; i <= m; ++i) if (scc[i] == scc[i+m]) return 0;
	if (!tp) return 1;
	int cnt = 0;
	for (i = 1; i <= m; ++i) cnt += scc[i+m] < scc[i];
	write(v),putchar(' '),write(cnt),putchar('
');
	for (i = 1; i <= m; ++i) if (scc[i+m] < scc[i]) write(i),putchar((--cnt)?' ':'
');
	return 1;
}

namespace sub0{
	int v[M],lv,cnt[N]; vector<int>G[N];
	inline bool chk(){
		int i,j,id,x,y;
		for (i = 1; i <= m; ++i) v[i] = ec[i]; sort(v+1,v+m+1),lv = unique(v+1,v+m+1)-v-1;
		for (i = 1; i <= m; ++i) ec[i] = lower_bound(v+1,v+lv+1,ec[i])-v,G[ec[i]].push_back(i);
		for (i = 1; i <= m; ++i) if (G[i].size()){
			for (j = 0; j < G[i].size(); ++j){
				id = G[i][j],x = ex[id],y = ey[id],++cnt[x],++cnt[y];
				if (cnt[x] > 2) return 0; if (cnt[y] > 2) return 0;
			}
			for (j = 0; j < G[i].size(); ++j) id = G[i][j],x = ex[id],y = ey[id],--cnt[x],--cnt[y];
		}
		return 1;
	}
}

int main(){
	int i;
	read(n),read(m);
	for (i = 1; i <= m; ++i) read(ex[i]),read(ey[i]),read(ec[i]),read(et[i]);
	if (!sub0::chk()){ puts("No"); return 0; }
	work();
	int L = 0,R = 1e9 + 7,Mid,Ans = R;
	while (L <= R){ Mid = L+R>>1; if (check(Mid,0)) Ans = Mid,R = Mid - 1; else L = Mid + 1; }
	if (Ans > 1000000000) puts("No"); else puts("Yes"),check(Ans,1);
	return 0;
}
原文地址:https://www.cnblogs.com/s-r-f/p/13584308.html