1. 程式人生 > 實用技巧 >「SCOI2011」糖果

「SCOI2011」糖果

無非就是兩種關係 \(a < b, a \le b\),考慮建圖求解。兩種關係都在 \(a, b\) 間連有向邊,若 \(a < b\) 邊權為 \(1\),否則為 \(0\)

\(0\) 邊構成的連通分量必定取值相同,縮點後若不是 \(DAG\) 則必定無解,因為 \(1\) 出現在環中。否則就拓撲排序,求出每個連通分量的最低等級也就沒有入度的點到它的最長路,乘以它的大小即為對答案的貢獻。

#include <bits/stdc++.h>
using namespace std;
#define rep(i, a, b) for (int i = (a); i <= (b); i++)
#define per(i, a, b) for (int i = (a); i >= (b); i--)
#define fi first
#define se second
typedef long long LL;
typedef pair <int, int> P;
const int inf = 0x3f3f3f3f, mod = 1e9 + 7, N = 3e5 + 10;
template <typename T>
inline void rd_(T &x) {
	x = 0; int f = 1;
	char ch = getchar();
	while (ch > '9' || ch < '0') { if (ch == '-') f = -1; ch = getchar(); }
	while (ch >= '0' && ch <= '9') x = x*10 + ch - '0', ch = getchar();
	x *= f;
}

int n, m, d[N], cnt, tot, h[N], stk[N], siz[N], idx, dfn[N], low[N], top, scc, id[N], deg[N];
queue <int> q;
vector <P> g[N];
bool vis[N];
struct Edge {
	int to, next, w;
} e[N<<1];

void add_(int u, int v, int w) {
	e[++cnt] = (Edge) {v, h[u], w};
	h[u] = cnt;
}

void dfs_(int u) {
	vis[u] = 1, stk[++top] = u;
	low[u] = dfn[u] = ++idx;
	for (int v, i = h[u]; i; i = e[i].next)
		if (!e[i].w) {
			v = e[i].to;
			if (!dfn[v])
				dfs_(v), low[u] = min(low[u], low[v]);
			else
				if (vis[v]) low[u] = min(low[u], dfn[v]);
		} 
	if (low[u] == dfn[u]) {
		scc++;
		int x;
		do {
			vis[x = stk[top--]] = 0;
			siz[scc]++, id[x] = scc;
		} while (x != u);
	}
}

int main() {
	rd_(n), rd_(m);
	for (int x, a, b, i = 1; i <= m; i++) {
		rd_(x), rd_(a), rd_(b);
		if (x == 1) 
			add_(a, b, 0), add_(b, a, 0);
		if (x == 2)
			add_(a, b, 1);
		if (x == 3)
			add_(b, a, 0);
		if (x == 4)
			add_(b, a, 1);
		if (x == 5)
			add_(a, b, 0);
	}
	rep (i, 1, n)
		if (!dfn[i])
			dfs_(i);
	rep (u, 1, n)
		for (int v, i = h[u]; i; i = e[i].next) {
			v = e[i].to;
			if (e[i].w || id[u] != id[v])
				g[id[u]].push_back(P(id[v], e[i].w)), deg[id[v]]++;
		}
	rep (i, 1, scc)
		if (!deg[i]) 
			q.push(i), d[i] = 1;
	LL ans = 0;
	while (!q.empty()) {
		int u = q.front(); 
		q.pop(), scc--, ans += 1ll*siz[u]*d[u];
		for (int v, i = 0; i < (int) g[u].size(); i++) {
			v = g[u][i].fi;
			d[v] = max(d[v], d[u] + g[u][i].se);
			if (!--deg[v])
				q.push(v);
		} 
	}
	if (scc)
		puts("-1");
	else
		printf("%lld\n", ans);
}