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(山东理工职业学院)在Java教学方面,通常会涵盖Java编程基础、面向对象编程、异常处理、集合框架、流式编程、文件操作以及数据库访问等内容。Java作为一种广泛使用的编程语言,因其平台无关性、面向对象、安全性等特点,在高校及企业中非常受欢迎。在教学过程中,学生会通过理论学习和实践练习来掌握Java语言的核心概念和应用。 学生在学习Java时,会逐步了解如何使用Java开发环境,例如安装JDK、配置环境变量等,之后会通过编写小程序来实践基本语法,如数据类型、控制流(if-else、switch、循环等)、数组的使用等。进一步,学生将学习类与对象的创建和使用,掌握继承、多态等面向对象编程的基本概念,并通过接口和抽象类的应用来实现多态。 异常处理方面,学生会学习如何捕获和处理运行时可能出现的错误,提高程序的健壮性。Java的集合框架,包括List、Set、Map等接口和实现类,是处理数据集合的重要工具,学生会学习如何操作这些集合。流式编程是Java 8引入的一个重要特性,学生会学习Lambda表达式和Stream API的使用,以实现更加简洁和高效的数据处理。 文件操作和数据库访问是Java应用程序与数据存储交互的常见方式。学生会学习如何使用Java I/O类读写文件,以及使用JDBC与关系数据库进行数据的存取操作。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值