题意:n个点,m个相连边,q是询问次数。每次输入一个数代表把这个点涂黑,问每次整个图有多少白点。 黑点也可以涂白。
#include <cstdio>
#include <cmath>
#include <iostream>
#include <algorithm>
#include <vector>
#include <stack>
#include <cstring>
#include <queue>
#include <set>
#include <string>
#include <map>
#include <climits>
#define PI acos(-1)
using namespace std;
typedef long long ll;
typedef double db;
const int maxn = 3e2 + 5;
const int mod = 1e9 + 7;
const int INF = 1e8 + 5;
const ll inf = 1e18 + 5;
const db eps = 1e-5;
int n, m, q, pos[maxn], du[maxn];
vector<int> G[maxn], fa[maxn];
void init()
{
for (int i = 1; i <= n; i++) G[i].clear(), fa[i].clear();
memset(du, 0, sizeof(du));
}
int get(int x)
{
return x == 0 ? 0 : (get(x>>1) + (x & 1));//每一位是否选中
}
void solve()
{
while (cin >> n >> m >> q)
{
init();
for (int i = 1; i <= m; i++)
{
int u, v; scanf("%d%d", &u, &v);
G[u].push_back(v);
fa[v].push_back(u);
du[v]++;
}
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= n; j++)
{
if (du[j] == 0)
{
du[j]--;
pos[i] = j;//拓扑排序存下连接点
for (int k = 0; k < G[j].size(); k++)
du[G[j][k]]--;
break;
}
}
}
int vis[maxn] = {0};
while (q--)
{
int x; scanf("%d", &x);
vis[x] ^= 1;//是否涂黑
int dp[maxn][11] = {0};
for (int i = 1; i <= n; i++)
{
int h = pos[i];
if (vis[h] == 1)
{
for (int j = 0; j < 10; j++)
dp[h][j] = 0;
continue;
}
int xx = (h - 1) / 30;//1-30 31-60 61-90
int hh = h % 30;//把300压到10 bit优化
dp[h][xx] |= (1 << hh);
for (int j = 0; j < fa[h].size(); j++)
{
int tmp = fa[h][j];
for (int k = 0; k < 10; k++)
dp[h][k] |= dp[tmp][k];//是否联通
}
}
int ans = 0;
for (int i = 1; i <= n; i++)
{
int tmp = 0;
for (int j = 0; j < 10; j++)
{
tmp += get(dp[i][j]);
}
if (tmp) ans += tmp - 1;
}
cout << ans << endl;
}
}
}
int main()
{
int t = 1, cas = 1;
// freopen("in.txt", "r", stdin);
// freopen("out.txt", "w", stdout);
// init();
// scanf("%d", &t);
while(t--)
{
// printf("Case %d: ", cas++);
solve();
}
return 0;
}