luogu P3387 【模板】缩点_拓扑排序

Code:

#include <stack>
#include <cstdio>
#include <algorithm>
#include <queue>
#include <cstring>
#include <map>
#define setIO(s) freopen(s".in","r",stdin)
using namespace std;
namespace Tarjan{
    #define maxn 1000000
    #define ll long long
    map<int,int>ed[maxn];
    int scc,sig;
    int vis[maxn];
    int du[maxn];
    int idx[maxn];
    int pre[maxn],low[maxn];
    int val[maxn];
    long long value[maxn];
    long long ans[maxn];
    stack<int>S;
    queue<int>Q;
    struct graph{
        int cnt;
        int head[maxn],to[maxn<<1],nex[maxn<<1];
        void addedge(int u,int v){
            nex[++cnt] = head[u],head[u]=cnt,to[cnt] = v;
        }
    }G1,G2;
    void tarjan(int u){
        S.push(u);
        vis[u] = 1;
        pre[u] = low[u] = ++scc;
        for(int v=G1.head[u];v;v=G1.nex[v]){
            if(!vis[G1.to[v]]) {
                tarjan(G1.to[v]);
                low[u] = min(low[u],low[G1.to[v]]);
            }
            else if(vis[G1.to[v]] == 1) low[u] = min(low[u],pre[G1.to[v]]);
        }
        if(pre[u] == low[u]) {
            ++sig;
            for(;;){
                int a=S.top(); S.pop();
                vis[a] = -1,idx[a] = sig;
                value[sig] += (ll)val[a];
                if(a==u) break;
            }
        }
    }
    void toposort(){
        for(int i=1;i<=sig;++i)
            for(int j=G2.head[i];j;j=G2.nex[j])   ++du[G2.to[j]];
        for(int i=1;i<=sig;++i) if(du[i]==0) Q.push(i),ans[i] = value[i];
        while(!Q.empty()){
            int u=Q.front(); Q.pop();
            for(int v=G2.head[u];v;v=G2.nex[v]){
                ans[G2.to[v]] = max(ans[G2.to[v]],ans[u] + value[G2.to[v]]);
                --du[G2.to[v]];
                if(du[G2.to[v]]==0) Q.push(G2.to[v]);
            }
        }
        long long fin=0;
        for(int i=1;i<=sig;++i)
            fin=max(fin,ans[i]);
        printf("%lld",fin);
    }
    int main(){
        int n,m,a,b;
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;++i) scanf("%d",&val[i]);
        for(int i=1;i<=m;++i) {
            scanf("%d%d",&a,&b);
            G1.addedge(a,b);
        }
        for(int i=1;i<=n;++i) if(!vis[i]) tarjan(i);
        for(int i=1;i<=n;++i)
            for(int v=G1.head[i];v;v=G1.nex[v])
                if(idx[i]!=idx[G1.to[v]] && !ed[idx[i]][idx[G1.to[v]]])
                    G2.addedge(idx[i],idx[G1.to[v]]),ed[idx[i]][idx[G1.to[v]]]=1;
        toposort();
        return 0;
    }
};
int main(){
    Tarjan::main();
    return 0;
}

  

原文地址:https://www.cnblogs.com/guangheli/p/10658410.html

时间: 2024-07-29 21:12:36

luogu P3387 【模板】缩点_拓扑排序的相关文章

b2OJ_1565_[NOI2009]植物大战僵尸_拓扑排序+最大权闭合子图

b2OJ_1565_[NOI2009]植物大战僵尸_拓扑排序+最大权闭合子 题意:n*m个植物,每个植物有分数(可正可负),和能保护植物的位置.只能从右往左吃,并且不能吃正被保护着的,可以一个不吃,求获得的最大分数. 分析:把每个植物向能保护它的植物连边.源点连正权点,负权点连汇点. 考虑在一个环上的植物是吃不到的,我们可以用拓扑排序确定哪些是能吃的. 然后求一遍最大权闭合子图就是答案. 代码: 1 #include <stdio.h> 2 #include <string.h>

【BZOJ-1924】所驼门王的宝藏 Tarjan缩点(+拓扑排序) + 拓扑图DP

1924: [Sdoi2010]所驼门王的宝藏 Time Limit: 5 Sec  Memory Limit: 128 MBSubmit: 787  Solved: 318[Submit][Status][Discuss] Description Input 第一行给出三个正整数 N, R, C. 以下 N 行,每行给出一扇传送门的信息,包含三个正整数xi, yi, Ti,表示该传送门设在位于第 xi行第yi列的藏宝宫室,类型为 Ti.Ti是一个1~3间的整数, 1表示可以传送到第 xi行任意

hihoCoder#1185 : 连通性&#183;三 tarjan求强联通分量 缩点 dfs/拓扑排序求路径和最大值

题目链接: http://hihocoder.com/problemset/problem/1185# 题意: n个点,每个点有一个权值,m条有向边,从1出发,每走到一个点, 就吃掉这个点的草,当没有可以到达的草场或是能够到达的草场都已经被吃光了之后就要返回到1了.求最多可以吃掉多少草. 思路: 提示里面讲的挺好的 如果草场是一个强连通图,那么我们只要走到任意一点,就可以把其他所有的草场都走一遍,并且可以选择任意一个点作为终点.所以把强联通块缩成一个点 因为一个强连通块会被缩成一个点,那么我们可

NOIP 车站分级 (luogu 1983 &amp; codevs 3294 &amp; vijos 1851) - 拓扑排序 - bitset

描述 一条单向的铁路线上,依次有编号为 1, 2, ..., n 的 n 个火车站.每个火车站都有一个级别,最低为 1 级.现有若干趟车次在这条线路上行驶,每一趟都满足如下要求:如果这趟车次停靠了火车站 x,则始发站.终点站之间所有级别大于等于火车站 x 的都必须停靠.(注意:起始站和终点站自然也算作事先已知需要停靠的站点)例如,下表是 5 趟车次的运行情况.其中,前 4 趟车次均满足要求,而第 5 趟车次由于停靠了 3 号火车站(2 级)却未停靠途经的 6 号火车站(亦为 2 级)而不满足要求

[Luogu P3953] 逛公园 (最短路+拓扑排序+DP)

题面 传送门:https://www.luogu.org/problemnew/show/P3953 Solution 这是一道神题 首先,我们不妨想一下K=0,即求最短路方案数的部分分. 我们很容易可以想到一个做法,就是魔改迪杰斯特拉做法: 如果一个点可以更新到达其他点的距离,那个点的方案数就是这个点的方案数:如果一个点所更新出来的距离和之前的相等,那个点的方案数加等当前点的方案数. 用式子可以表现为: f[j]=f[i] (dis[j]>dis[i]+x)   f[j]+=f[i] (dis

【Luogu】P3116会议时间(拓扑排序,DP)

题目链接 本题使用拓扑排序来规划DP顺序.设s[i][j]表示i步是否能走到j这个点,e[i][j]表示i步是否能走到j这个点——用第二条路径.因为要满足无后效性和正确性,只有第i个点已经全部更新完毕的时候才能用它来更新其他的点.所以用拓扑. 代码如下 #include<cstdio> #include<cctype> #include<cstring> #include<algorithm> using namespace std; inline long

数据结构课程笔记_拓扑排序

何谓拓扑排序? 由某个集合上的一个偏序得到该集合上的一个全序,这个操作叫做拓扑排序. 如何得到一个有向图的拓扑排序? 按照有向图给出的次序关系,将图中顶点排成一个线性序列,对于有向图中没有限定次序关系的顶点,则可以人为加上任意的次序关系,由此所得顶点的线性序列称之为拓扑有序序列. 如何进行拓扑排序? 1.从有向图中选取一个没有前驱的顶点: 2.从有向图中删去此顶点以及所有以它为尾的弧: 重复上述两步直至图空,或者图中找不到无前驱的顶点为止,后一种情况说明图中有环. 算法中需要用定量描述代替定性概

[bzoj1565][NOI2009]植物大战僵尸_网络流_拓扑排序

植物大战僵尸 bzoj1565 题目大意:给你一张网格图,上面种着一些植物.你从网格的最右侧开始进攻.每个植物可以对僵尸提供能量或者消耗僵尸的能量.每个植物可以保护一个特定网格内的植物,如果一个植物被保护,那么如果僵尸想吃掉该植物就必须先吃掉保护它的植物.问:僵尸最多能获得多少能量. 注释:1<=N(网格的宽)<=20,1<=M(网格的长)<=30,-20,000<=代价和收益<=20,000. 想法:前置题目([NOI2006]最大获利).这道题和最大获利比较相像,如

图论_拓扑排序

对一个有向无环图(Directed Acyclic Graph简称DAG)G进行拓扑排序,是将G中所有顶点排成一个线性序列,使得图中任意一对顶点u和v,若边(u,v)∈E(G),则u在线性序列中出现在v之前. 通常,这样的线性序列称为满足拓扑次序(Topological Order)的序列,简称拓扑序列.简单的说,由某个集合上的一个偏序得到该集合上的一个全序,这个操作称之为拓扑排序. 执行步骤 由AOV网构造拓扑序列的拓扑排序算法主要是循环执行以下两步,直到不存在入度为0的顶点为止. (1) 选