SDUT 2170 The Largest SCC

一句话题意:

​ 给出一个点数 n1000 边数 m20000 的有向图,一共 Q20000 次询问,询问相互独立,每次询问如果将第 x(1xm) 条边变为无向边时,图中最大的强连通分量所包含的点数为多少

首先做一次强连通分量的缩点肯定是不吃亏的(笑

如果第 x 条边的两个端点在同一个强连通分量内,其实这一次的更改边对缩点后的图是没有更改的,所以答案是原图中点最多的强连通分量

如果第 x 条边的两个端点不在同一个强连通分量内,不妨记该边的端点所在的强连通分量为 start end ,到那么这一次更改边会影响到的点其实就是从 start 出发到 end 中间所有能经过的点,也就是说,这些点在改边之后会被缩到一个联通分量内,那么只要统计出来就好了

具体的代码实现的,我们可以先预处理一个 visx,y 这样二维的 bool 矩阵,表示出来从 x 出发是否能到达 y ,这部分我们能通过 n dfs bfs 解决,然后每一次询问可以 O(n) 地回答,总的时间复杂度是 O(n+n2+n×Q)

我是代码的分割线

#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;
}

你可能感兴趣的:(SDUT 2170 The Largest SCC)