题意:
给定 n n n个点, m m m条边的有向图,初始每个点颜色是白色, q q q次操作,每次操作将某个节点的颜色取反(白变黑,黑边白),每次操作求出二元组 ( u , v ) (u,v) (u,v),从 u u u 到 v v v 的路径上无白色顶点的路径数。
思路:
暴力修改点,每次修改后 d f s dfs dfs一遍求路径, d p [ u ] dp[u] dp[u]表示以 u u u为初始点的路径数
转移:
d
p
[
u
]
+
=
d
p
[
v
]
dp[u] += dp[v]
dp[u]+=dp[v]。 显然对于一个点
u
u
u,满足的路径数就是满足条件的点数,那么想要知道
d
p
[
u
]
dp[u]
dp[u],
就要知道有多少个点与
u
u
u的路径上无黑色的点,而且每个点不能重复计算,所以复杂度为
O
(
q
n
3
)
O(qn^3)
O(qn3)。 所以我们用
b
i
t
s
e
t
bitset
bitset来优化统计答案的部分,
b
i
t
[
i
]
bit[i]
bit[i]表示点
i
i
i对答案的贡献,答案就是
b
i
t
[
i
]
bit[i]
bit[i]中 1 的数目。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 355;
vector<int>v[maxn];
bitset<maxn>bit[maxn];
int vis[maxn],col[maxn];
int n,m,q;
void dfs(int u,int fa){
vis[u] = 1;
bit[u][u] = 1;
if(col[u] == 1) return;
for(auto vv:v[u]){
if(vv == fa) continue;
if(!vis[vv])
dfs(vv,u);
if(col[vv] == 1) continue;
bit[u] |= bit[vv];
}
}
int main(){
while(~scanf("%d%d%d",&n,&m,&q)){
for(int i = 0; i <= n; i++) v[i].clear();
for(int i = 1; i <= m; i++){
int a,b;
scanf("%d%d",&a,&b);
v[a].push_back(b);
}
for(int i = 0; i < maxn; i++) bit[i].reset(),vis[i] = 0,col[i] = 0;
ll ans = 0;
while(q--){
ans = 0;
int x;
scanf("%d",&x);
col[x] ^= 1;
for(int i = 1; i <= n; i++) vis[i] = 0,bit[i].reset();
for(int i = 1; i <= n; i++){
if(!vis[i])
dfs(i,0);
ans += bit[i].count()-1;
}
printf("%lld\n",ans);
}
}
}