[APIO2009]抢掠计划

【题目描述】:
抢掠计划

【思路】:
个人认为\(APIO\)考这种题完全是在搞笑,可能是怕有些选手一道题都\(A\)不了而设置的吧(比如我)。

\(tarjan\)裸题,先缩点,在\(DAG\)上跑一遍\(dp\)决策出最大利益,因为终点处必须要有酒吧。所以最后在有酒吧的点处选最大值就可以了。。

水水水。。

#include<cstdio>
#include<cstring>
#include<queue>
#define inf 0x3f3f3f3f
using namespace std;

int n,m,st,p;

const int MAXN = 500005;

struct edge{
    int u,v,nxt;
}e[MAXN];int head[MAXN];int cnt = 0;int x[MAXN];int y[MAXN];int mon[MAXN];int pub[MAXN];
int dfn[MAXN];int low[MAXN];int s[MAXN];int id = 0;int tot = 0;int Bcnt = 0;bool vis[MAXN];int b[MAXN];int val[MAXN];
int dis[MAXN];bool r[MAXN];int bill[MAXN];

inline void add(int u,int v){
    e[++cnt].u = u;e[cnt].v = v;e[cnt].nxt = head[u];head[u] = cnt;
}

inline void tarjan(int x){
    dfn[x] = low[x] = ++id;
    s[++tot] = x;vis[x] = 1;

    for(int i=head[x];i;i=e[i].nxt){
        int v = e[i].v;
        if(!dfn[v]){
            tarjan(v);
            low[x] = min(low[x] , low[v]);
        }
        else if (vis[v]) low[x] = min(low[x] , dfn[v]);
    }

    if(low[x] == dfn[x]){
        int j = -1;Bcnt++;
        while(j ^ x){
            j = s[tot--];
            vis[j] = 0;
            b[j] = Bcnt;
            val[Bcnt] += mon[j];
            if(pub[j]) bill[Bcnt] = 1;
        }
    }
}

queue<int>q;
inline void spfa(){
    q.push(b[st]);
    memset(dis,-inf,sizeof dis);dis[b[st]] = val[b[st]];
    
    while(!q.empty()){
        int u = q.front();q.pop();r[u] = 0;
        for(int i=head[u];i;i=e[i].nxt){
            int v = e[i].v;
            if(dis[v] < dis[u] + val[v]){
                dis[v] = dis[u] + val[v];
                if(!r[v]){
                    q.push(v);
                    r[v] = 1;
                }
            }
        }
    }
    
//	for(int i=1;i<=Bcnt;++i) printf("%d ",dis[i]);
    int ans = -inf;
    for(int i=1;i<=Bcnt;++i){
        if(bill[i]) ans = max(ans , dis[i]);
    }
    printf("%d",ans);
}

int main(){
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;++i){
        int u,v;scanf("%d%d",&u,&v);
        x[i] = u;y[i] = v;
        add(u,v);
    }
    for(int i=1;i<=n;++i) scanf("%d",&mon[i]);
    scanf("%d%d",&st,&p);
    for(int i=1;i<=p;++i){
        int o;scanf("%d",&o);
        pub[o] = 1;
    }

    for(int i=1;i<=n;++i) if(!dfn[i]) tarjan(i);
    
    memset(head,0,sizeof head);cnt = 0;
    for(int i=1;i<=m;++i) if(b[x[i]] ^ b[y[i]]) add(b[x[i]] , b[y[i]]);
    
    spfa();
    return 0;
}
posted @ 2018-09-22 23:04  lajioj  阅读(154)  评论(0编辑  收藏  举报