APIO2009劫掠计划

/*
缩点加上最长路
应该用拓扑序列的  不想写  spfa跑一下吧

*/

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<queue>
#include<iostream>
#define M 500200
#define ll long long
using namespace std;
int be[M], ed[M], to[M], nxt[M], dft, head[M], cnt, belong[M], dfn[M], low[M], dis[M], ver[M], ver2[M], st[M], top, tot;
bool vis[M], isj[M], zz[M];

int read() {
    int nm = 0, f = 1;
    char c = getchar();
    for(; !isdigit(c); c = getchar()) if(c == ‘-‘) f = -1;
    for(; isdigit(c); c = getchar()) nm = nm * 10 + c -‘0‘;
    return nm * f;
}

void push(int vi, int vj) {
    cnt++;
    to[cnt] = vj;
    nxt[cnt] = head[vi];
    head[vi] = cnt;
}

void tarjan(int x) {
    dfn[x] = low[x] = ++dft;
    st[++top] = x;
    vis[x] = true;
    for(int i = head[x]; i; i = nxt[i]) {
        int vj = to[i];
        if(!dfn[vj]) {
            tarjan(vj);
            low[x] = min(low[x], low[vj]);
        } else if(vis[vj]) low[x] = min(low[x], dfn[vj]);
    }
    if(dfn[x] == low[x]) {
        tot++;
        while(st[top] != x) {
            belong[st[top]] = tot;
            ver2[tot] += ver[st[top]];
            if(isj[st[top]]) zz[tot] = true;
            vis[st[top]] = false;
            top--;
        }

        belong[st[top]] = tot;
        ver2[tot] += ver[st[top]];
        if(isj[st[top]]) zz[tot] = true;
        vis[st[top]] = false;
        top--;
    }
}

void spfa(int x) {
    queue<int>q;
    dis[x] = ver2[x];
    memset(vis, 0, sizeof(vis));
    q.push(x);
    while(!q.empty()) {
        int op = q.front();
        q.pop();
        vis[op] = false;
        for(int i = head[op]; i; i = nxt[i]) {
            int vj = to[i];
            if(dis[vj] < dis[op] + ver2[vj]) {
                dis[vj] = dis[op] + ver2[vj];
                if( !vis[vj])
                    q.push(vj), vis[vj] = true;
            }
        }
    }
}

int main() {
    int n = read(), m = read();
    for(int i = 1; i <= m; i++) {
        be[i] = read(), ed[i] = read();
        push(be[i], ed[i]);
    }
    for(int i = 1; i <= n; i++) ver[i] = read();
    int s = read(), k = read();
    for(int i = 1; i <= k; i++) isj[read()] = true;
    tarjan(s);
    memset(head, 0, sizeof(head));
    cnt = 0;
    for(int i = 1; i <= m; i++) {
        int vi = belong[be[i]], vj = belong[ed[i]];
        if(vi == vj) continue;
        push(vi, vj);
    }
    spfa(belong[s]);
    int ans=  0;
    for(int i = 1; i <= tot; i++) {
        if(zz[i]) ans = max(ans, dis[i]);
    }
    cout << ans;
    return 0;
}

原文地址:https://www.cnblogs.com/luoyibujue/p/9240866.html

时间: 2024-07-30 20:25:51

APIO2009劫掠计划的相关文章

APIO2009 抢掠计划 Tarjan DAG-DP

APIO2009 抢掠计划 Tarjan DAG-DP 题面 一道\(Tarjan\)缩点水题.因为可以反复经过节点,所以把一个联通快中的所有路口看做一个整体,缩点后直接跑spfa或者dp就好了. 我选择了在DAG上跑dp,毕竟复杂度\(O(n)\) 拓扑时搞DP,\(f[i]\)表示在DAG上\(i\)节点时,当前最大钱数,转移\(f[v]=max(f[v], f[u]+w[v])?\) #include <cstdio> #include <queue> #define MAX

【p3627】[APIO2009] 抢掠计划

Description Siruseri 城中的道路都是单向的.不同的道路由路口连接.按照法律的规定, 在每个路口都设立了一个 Siruseri 银行的 ATM 取款机.令人奇怪的是,Siruseri 的酒吧也都设在路口,虽然并不是每个路口都设有酒吧. Banditji 计划实施 Siruseri 有史以来最惊天动地的 ATM 抢劫.他将从市中心 出发,沿着单向道路行驶,抢劫所有他途径的 ATM 机,最终他将在一个酒吧庆 祝他的胜利. 使用高超的黑客技术,他获知了每个 ATM 机中可以掠取的现金

[APIO2009]抢掠计划

题目描述 Siruseri 城中的道路都是单向的.不同的道路由路口连接.按照法律的规定, 在每个路口都设立了一个 Siruseri 银行的 ATM 取款机.令人奇怪的是,Siruseri 的酒吧也都设在路口,虽然并不是每个路口都设有酒吧. Banditji 计划实施 Siruseri 有史以来最惊天动地的 ATM 抢劫.他将从市中心 出发,沿着单向道路行驶,抢劫所有他途径的 ATM 机,最终他将在一个酒吧庆 祝他的胜利. 使用高超的黑客技术,他获知了每个 ATM 机中可以掠取的现金数额.他希 望

【bzoj1179】[Apio2009]抢掠计划atm 强连通分量缩点+spfa

Input 第一行包含两个整数N.M.N表示路口的个数,M表示道路条数.接下来M行,每行两个整数,这两个整数都在1到N之间,第i+1行的两个整数表示第i条道路的起点和终点的路口编号.接下来N行,每行一个整数,按顺序表示每个路口处的ATM机中的钱数.接下来一行包含两个整数S.P,S表示市中心的编号,也就是出发的路口.P表示酒吧数目.接下来的一行中有P个整数,表示P个有酒吧的路口的编号 Output 输出一个整数,表示Banditji从市中心开始到某个酒吧结束所能抢劫的最多的现金总数. Sample

洛谷3627 [APIO2009]抢掠计划

题目描述 输入格式: 第一行包含两个整数 N.M.N 表示路口的个数,M 表示道路条数.接下来 M 行,每行两个整数,这两个整数都在 1 到 N 之间,第 i+1 行的两个整数表示第 i 条道路的起点和终点的路口编号.接下来 N 行,每行一个整数,按顺序表示每 个路口处的 ATM 机中的钱数.接下来一行包含两个整数 S.P,S 表示市中心的 编号,也就是出发的路口.P 表示酒吧数目.接下来的一行中有 P 个整数,表示 P 个有酒吧的路口的编号. 输出格式: 输出一个整数,表示 Banditji

【长沙集训】2017.9.12

并不怎么傻逼的题也把自己考成傻逼.大概是全机房最后几个改完题的人了..QAQ T1 APIO2009抢掠计划 好像是之前哪位学长讲过,tarjan缩点,然后值取反跑spfa或者拓扑排序后做Dp;考场上(第一次)尝试拓扑后DP,然后十分SB地一开始只放进了起点,认为其余入度为0的点无所谓(能过那么多点也是神奇).实际上显然需要把所有入读为0的点放入栈中,dp值初始为最大,起点为0,然后一边拓扑一边dp: //Twenty #include<cstdio> #include<cstdlib&

大神刷题表

9月27日 后缀数组:[wikioi3160]最长公共子串 dp:NOIP2001统计单词个数 后缀自动机:[spoj1812]Longest Common Substring II [wikioi3160]最长公共子串 [spoj7258]Lexicographical Substring Search 扫描线+set:[poj2932]Coneology 扫描线+set+树上删边游戏:[FJOI2013]圆形游戏 结论:[bzoj3706][FJ2014集训]反色刷 最小环:[poj1734

算法详解之缩点

前置技能:tarjan求强连通分量 缩点. 顾名思义,就是在图论算法中将一些点缩成一个点的一种算法. 应用 貌似明白了,但是这有什么用呢? 我们经常求最短路,但是如果我们要求最长路呢? 标准问法: 给你一张有向图,每个点都有一个点权(不是边权了哦),且每一个点都可以经过任意多次,但是点权只能加一次,求这张图的最大权值 题目分析: 看到这,相信大多数人都会想到把最短路的模板改一下就行了,但是这会出问题,你会在一个圈里团团转. 怎么办办? 我们会发现,只要是一堆可以构成强连通分量的点,我们就可以将它

2019年7月训练(壹)

2019-07-25 luogu P3627 [APIO2009]抢掠计划 卡了三个小时,看了题解才作出来的(菜) 前驱知识: 壹~邻接表存储/遍历 贰~SPFA跑最长路(<改>就行了) 叄~Tarjan缩点 壹.邻接表储存 两个,add存无边权,未缩点:build有边权,已缩点. void add(int u,int v) { cnt++; e[cnt].to=v; e[cnt].next=head[u]; head[u]=cnt; } void build(int u,int v,int