CF1215F Radio Stations

CF1215F Radio Stations
难啊,没搞懂怎么前缀和优化建边,于是瞄了一眼题解。。。

大概就是对于一个点 \(x\)\(yes(x)\) 代表 \(f \in [1, x]\)\(no(x)\) 代表 \(f \in [x+1, M]\)。所以对于一个电台的区间 \([l,r]\) 即为 \(yes(r) \ \& \ no(l-1)\)。然后就再开 \(2M\) 个点表示一下。
剩下就是 \(\text{2-sat}\) 板子。
根据情况连边。

  • “至少”连 \(\lnot x \rightarrow y, \lnot y \rightarrow x\)
  • “至多”连 \(x \rightarrow \lnot y, y \rightarrow \lnot x\)
  • 然后框边界 \(x \rightarrow \lnot (P+l-1), (P+l-1) \rightarrow \lnot x, x \rightarrow (P+r), \lnot(P+r) \rightarrow \lnot x\)

然后跑 \(\text{2-sat}\)

/*
	Name:
	Author: Gensokyo_Alice
	Date:
	Description:
*/
#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <vector>
#include <queue>
#include <stack>
#include <cmath>
#include <ctime>
#include <map>
#include <set>

using namespace std;

typedef long long ll;
const ll MAXN = 2e6+10;

ll N, P, M1, M2, _N, cnt, num, vis[MAXN], dfn[MAXN], low[MAXN], head[MAXN], bel[MAXN];
stack <ll> st;

struct edge {
	ll nt, to;
} E[MAXN << 1];

ll no(ll);
ll yes(ll);
bool calc();
void tarjan(ll);
void add(ll, ll);

int main() {
	memset(head, -1, sizeof(head));
	scanf("%lld%lld%lld%lld", &N, &P, &M1, &M2); // 0 ~ P-1;
	for (ll i = 1, x, y; i <= N; i++) {
		scanf("%lld%lld", &x, &y); x--, y--;
		add(no(y), yes(x));
		add(no(x), yes(y));
	}
	for (ll i = 0; i < M1; i++) {
		add(yes(i+P), yes(i+P+1));
		add(no(i+P+1), no(i+P));
	}
	add(yes(P), no(P));
	for (ll l, r, i = 0; i < P; i++) {
		scanf("%lld%lld", &l, &r);
		add(yes(i), no(P+l-1));
		add(yes(P+l-1), no(i)); 
		add(yes(i), yes(P+r));
		add(no(P+r), no(i));
	}
	for (ll i = 1, x, y; i <= M2; i++) {
		scanf("%lld%lld", &x, &y); x--, y--;
		add(yes(x), no(y));
		add(yes(y), no(x));
	}
	if (calc()) {
		ll k = 0;
		for (ll i = 0; i < P; i++) if (bel[yes(i)] < bel[no(i)]) k++;
		for (ll i = 1; i <= M1; i++) if (bel[yes(i+P)] < bel[no(i+P)]) {printf("%lld %lld\n", k, i); break;}
		for (ll i = 0; i < P; i++) if (bel[yes(i)] < bel[no(i)]) printf("%lld ", i+1);
	} else puts("-1");
    return 0;
}

ll no(ll x) {return x << 1 | 1;}
ll yes(ll x) {return x << 1;}

bool calc() {
	for (ll i = 0; i <= no(M1+P); i++) if (!dfn[i]) tarjan(i);
	for (ll i = 0; i <= M1+P; i++) if (bel[yes(i)] == bel[no(i)]) return false;
	return true;
}

void tarjan(ll n) {
	dfn[n] = low[n] = ++num;
	st.push(n); vis[n] = 1;
	for (ll i = head[n]; ~i; i = E[i].nt) {
		ll v = E[i].to;
		if (!dfn[v]) {
			tarjan(v);
			low[n] = min(low[v], low[n]);	
		} else if (vis[v]) low[n] = min(dfn[v], low[n]);
	}
	if (dfn[n] == low[n]) {
		_N++;
		ll t;
		do {
			t = st.top();
			st.pop();
			bel[t] = _N;
			vis[t] = 0;
		} while (t != n);
	}
}

void add(ll x, ll y) {
	cnt++;
	E[cnt].to = y;
	E[cnt].nt = head[x];
	head[x] = cnt;
}
posted @ 2020-11-17 10:59  Gensokyo_Alice  阅读(56)  评论(0编辑  收藏  举报