Live2D

CF1062F Upgrading Cities

link

Solution

首先可以看出,次重要其实就是只有一个点它不能到也不能到它。又因为这是DAG,所以它能到的点与能到它的点是不交的。所以我们可以分开求,以下即考虑可到点集。

那么我们显然有一个 \(\Theta(n^2/\omega)\) 的做法,即是用 bitset 维护可到点集。可以发现没有前途。

考虑到拓扑排序存在以下性质:

任一时刻队列中的点不存在可达性关系。

这个可以证明,因为它连出的节点只有在它弹出队列之后才能加入。

那么如果对于当前节点,如果队列大小 \(\ge 3\),那么这个一定没戏,可以先排除掉这些点。如果队列大小为 \(1\),那么设 \(t\) 为 topo 序在此之前的点的数量,那么可达点数就是 \(n-t\)。对于队列大小为 \(2\) 的情况,假如为 \(u,v\),那么只有 \(u\) 能到达 topo 序在两者之后的所有点才能合法,可以看出如果 \(v\) 连出的点 \(x\),如果存在 \(\text{deg}_x=1\),那么显然不合法,否则可达点数就是 \(n-t-1\)

Code

#include <bits/stdc++.h>
using namespace std;

#define Int register int
#define int long long
#define MAXN 300005

template <typename T> inline void read (T &t){t = 0;char c = getchar();int f = 1;while (c < '0' || c > '9'){if (c == '-') f = -f;c = getchar();}while (c >= '0' && c <= '9'){t = (t << 3) + (t << 1) + c - '0';c = getchar();} t *= f;}
template <typename T,typename ... Args> inline void read (T &t,Args&... args){read (t);read (args...);}
template <typename T> inline void write (T x){if (x < 0){x = -x;putchar ('-');}if (x > 9) write (x / 10);putchar (x % 10 + '0');}
template <typename T> inline void chkmax (T &a,T b){a = max (a,b);}
template <typename T> inline void chkmin (T &a,T b){a = min (a,b);}

int n,m,s[MAXN],deg[MAXN];
vector <int> g[MAXN],H[MAXN];

void topo (){
	queue <int> q;int tot = 0;
	for (Int u = 1;u <= n;++ u) deg[u] = 0;
	for (Int u = 1;u <= n;++ u) for (Int v : H[u]) deg[v] ++;
	for (Int u = 1;u <= n;++ u) if (!deg[u]) q.push (u);
	while (!q.empty()){
		int u = q.front();q.pop (),tot ++;
		if (q.size() == 0) s[u] += n - tot;
		else if (q.size() == 1){
			int v = q.front();bool flg = 1;
			for (Int x : H[v]) if (deg[x] == 1){flg = 0;break;}
			if (flg) s[u] += n - tot - 1;
			else s[u] -= 1e9;
		}
		else s[u] -= 1e9;
		for (Int v : H[u]) if (!-- deg[v]) q.push (v);
	}
}

signed main(){
	read (n,m);
	for (Int i = 1,u,v;i <= m;++ i) read (u,v),g[u].push_back (v);
	for (Int u = 1;u <= n;++ u) H[u] = g[u];
	topo ();
	for (Int u = 1;u <= n;++ u) H[u].clear ();
	for (Int u = 1;u <= n;++ u) for (Int v : g[u]) H[v].push_back (u);
	topo ();
	int ans = 0;
	for (Int u = 1;u <= n;++ u) if (s[u] >= n - 2) ans ++;
	write (ans),putchar ('\n');
	return 0;
}
posted @ 2022-10-18 19:21  Dark_Romance  阅读(36)  评论(0编辑  收藏  举报