[APIO 2009] Atm

传送门:>Here<

题意:给出一个有向图(有环),每个点有点权。从点S出发,经过每个点Tot可以加上点权,点可以经过多次,然而点权不能重复加多次。先要求走到某个终点E时点权最大。先要求在给定的某些终点E终,点权之和的最大值。

解题思路:

  题目有点难懂。首先如果只是暴力搜索的话,由于有环会无限循环,而且环内的值只会加一次,很容易想到强连通分量缩点。然后SPFA(改一改,变成最大值)求出每个点的最大值就可以了。然而如果某一个强连通分量里有酒吧,那么走到这个强联通分量作为终点一定是可以的。因此加个判断就好了。还是很水的……

Code

  Nothing

/*By QiXingzhi*/
#include <cstdio>
#include <queue>
#include <cstring>
#define  r  read()
#define  Max(a,b)  (((a)>(b)) ? (a) : (b))
#define  Min(a,b)  (((a)<(b)) ? (a) : (b))
typedef long long ll;
using namespace std;
const int MAXN = 500010;
const int MAXM = 1000010;
const int INF = 0x3f3f3f3f;
inline int read(){
    int x = 0; int w = 1; register int c = getchar();
    while(c ^ '-' && (c < '0' || c > '9')) c = getchar();
    if(c == '-') w = -1, c = getchar();
    while(c >= '0' && c <= '9') x = (x << 3) +(x << 1) + c - '0', c = getchar();
    return x * w;
}
bool bar[MAXN];
queue <int> q;
vector <int> G[MAXN],G2[MAXN];
int N,M,dfs_clock,S,P,scc_cnt,top,_x,ans;
int p[MAXN],sccno[MAXN],dfn[MAXN],low[MAXN],sta[MAXN],x[MAXN],y[MAXN],d[MAXN],val[MAXN],win[MAXN];
inline void AddEdge(int u, int v){ G[u].push_back(v); }
inline void AddEdge2(int u, int v){ G2[u].push_back(v); }
inline void tarjan(int u){
    dfn[u] = low[u] = ++dfs_clock;
    sta[++top] = u;
    int sz = G[u].size(), v;
    for(int i = 0; i < sz; ++i){
        v = G[u][i];
        if(!dfn[v]){ tarjan(v); low[u] = Min(low[u], low[v]); }
        else if(!sccno[v]) low[u] = Min(low[u], dfn[v]);
    }
    int X;
    if(dfn[u] == low[u]){
        ++scc_cnt;
        while(1){
            X = sta[top--];
            if(bar[X]) win[scc_cnt] = 1;
            sccno[X] = scc_cnt;
            val[scc_cnt] += p[X];
            if(X == u) break;
        }
    }
}
inline void BFS(int s){
    d[s] = val[s];
    q.push(s);
    int cur,sz,v;
    while(!q.empty()){
        cur = q.front(), q.pop();
        sz = G2[cur].size();
        for(int i = 0; i < sz; ++i){
            v = G2[cur][i];
            if(d[cur] + val[v] > d[v]){ d[v] = d[cur] + val[v]; q.push(v); }
        }
    }
}
int main(){
    N = r, M = r;
    for(int i = 1; i <= M; ++i){ x[i] = r, y[i] = r; AddEdge(x[i], y[i]); }
    for(int i = 1; i <= N; ++i) p[i] = r;
    S = r, P = r;
    for(int i = 1; i <= P; ++i) _x = r, bar[_x] = 1;
    for(int i = 1; i <= N; ++i) if(!dfn[i]) tarjan(i);
    for(int i = 1; i <= M; ++i) if(sccno[x[i]] != sccno[y[i]]) AddEdge2(sccno[x[i]], sccno[y[i]]);
    BFS(sccno[S]);
    for(int i = 1; i <= N; ++i) if(win[i]) ans = Max(ans, d[i]);
    printf("%d", ans);
    return 0;
}
原文地址:https://www.cnblogs.com/qixingzhi/p/9353337.html