一句话题意:
给出一个点数 n≤1000 边数 m≤20000 的有向图,一共 Q≤20000 次询问,询问相互独立,每次询问如果将第 x(1≤x≤m) 条边变为无向边时,图中最大的强连通分量所包含的点数为多少
首先做一次强连通分量的缩点肯定是不吃亏的(笑
如果第 x 条边的两个端点在同一个强连通分量内,其实这一次的更改边对缩点后的图是没有更改的,所以答案是原图中点最多的强连通分量
如果第
具体的代码实现的,我们可以先预处理一个
visx,y
这样二维的
bool
矩阵,表示出来从
x
出发是否能到达
我是代码的分割线
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1123;
int dfn[maxn],low[maxn],_cnt;
int bel[maxn];
vector<int>edge[maxn];
vector<int>scc[maxn];
stack<int> S;
void init(int n){
for(int i=0;i<n;i++){
edge[i].clear();
}
while(S.empty()==false)
S.pop();
memset(dfn,-1,sizeof(dfn));
memset(low,-1,sizeof(low));
memset(bel,-1,sizeof(bel));
_cnt = 1;
}
void dfs(int st){
S.push(st);
dfn[st] = low[st] = _cnt++;
for(vector<int>::iterator it = edge[st].begin();it!=edge[st].end();it++){
int x = *it;
if(dfn[x] == -1){
dfs(x);
low[st] = min(low[st],low[x]);
}
else if(bel[x] == -1){
low[st] = min(low[st],dfn[x]);
}
}
if(low[st] == dfn[st]){
while(S.top()!=st){
bel[S.top()] = st;
S.pop();
}
bel[st] = st;
S.pop();
}
}
const int maxm = 21234;
int from[maxm],to[maxm];
int cnt[maxn];
bool viser[maxn][maxn];
void dffs(int st,bool *s){
s[st] = true;
for(vector<int>::iterator it = scc[st].begin();it!=scc[st].end();it++){
if(s[*it] == false){
dffs(*it,s);
}
}
}
void getvis(int n){
for(int i=1;i<=n;i++){
scc[i].clear();
}
for(int st = 1;st <= n;st++){
for(vector<int>::iterator it = edge[st].begin();it!=edge[st].end();it++){
int f = bel[st];
int t = bel[*it];
if(f != t){
scc[f].push_back(t);
}
}
}
memset(viser,0,sizeof(viser));
for(int i=1;i<=n;i++){
if(bel[i] == i){
dffs(i,viser[i]);
}
}
}
int main(){
int T;
scanf("%d",&T);
int n ,m;
int q;
while(T-- && ~scanf("%d %d %d",&n,&m,&q)){
init(n);
for(int i=1;i<=m;i++){
scanf("%d %d",&from[i],&to[i]);
edge[from[i]].push_back(to[i]);
}
for(int i=1;i<=n;i++){
if(bel[i] == -1){
dfs(i);
}
}
memset(cnt,0,sizeof(cnt));
for(int i=1;i<=n;i++){
cnt[bel[i]]++;
}
getvis(n);
int x;
int maxer = *max_element(cnt+1,cnt+1+n);
while(q--){
scanf("%d",&x);
int f = bel[from[x]],t = bel[to[x]];
if(f == t){
printf("%d\n",maxer);
}
else{
int ans = 0;
for(int i=1;i<=n;i++){
if(viser[f][i] && viser[i][t]){
ans += cnt[i];
}
}
printf("%d\n",max(maxer,ans));
}
}
}
return 0;
}