【jzoj4771】【爬山】【人工栈】【图论】【强连通分量】

70 篇文章 0 订阅
22 篇文章 0 订阅

题目大意

给出一幅有向图每个点有价值,要从起点走到一个给定的点集中的一个点才能停止,求最大价值,重复经过没有价值。

解题思路

tarjan后按拓扑序dp即可,坑的是点可能很多要打人工栈。

code

#include<set>
#include<cmath>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define LF double
#define LL long long
#define max(n1,n2) ((n1>n2)?n1:n2)
#define min(n1,n2) ((n1>n2)?n2:n1)
#define fo(i,j,k) for(LL i=j;i<=k;i++)
#define fd(i,j,k) for(LL i=j;i>=k;i--)
using namespace std;
int const maxn=500000,maxm=500000,inf=2147483647;
LL n,m,gra,top,top2,time,s,p,u[maxm+10],v[maxm+10],val[maxm+10],to[maxm+10],
next[maxm+10],begin[maxn+10],dfn[maxn+10],low[maxn+10],st[maxn+10],st2[maxn+10],
inst[maxn+10],bel[maxn+10],save[maxn+10],f[maxn+10],pre[maxn+10];
void insert(LL u,LL v){
    to[++gra]=v;
    next[gra]=begin[u];
    begin[u]=gra;
}
void tarjan(LL be){
    inst[st[++top]=be]=1;
    st2[++top2]=be;
    LL now;
    for(;top2;){
        now=st2[top2];
        if(save[st2[top2]]){
            int bb;
            bb++;
        }
        if(!dfn[now])dfn[now]=low[now]=++time;
        for(;begin[now];begin[now]=next[begin[now]])
            if(!dfn[to[begin[now]]]){
                inst[st[++top]=st2[++top2]=to[begin[now]]]=1;
                break;
            }else if(inst[to[begin[now]]])low[now]=min(low[now],dfn[to[begin[now]]]);
        if(!begin[now]){
            if(dfn[now]==low[now]){
                for(;st[top]!=now;bel[st[top]]=now,val[now]+=val[st[top]],save[now]|=save[st[top]],inst[st[top--]]=0);
                bel[st[top]]=now;inst[st[top--]]=0;
            }
            low[st2[top2-1]]=min(low[st2[top2-1]],low[st2[top2]]);
            st2[top2--];
        }
    }
}
int main(){
    freopen("d.in","r",stdin);
    freopen("d.out","w",stdout);
    scanf("%lld%lld",&n,&m);
    fo(i,1,m){
        scanf("%lld%lld",&u[i],&v[i]);
        insert(u[i],v[i]);
    }
    fo(i,1,n)scanf("%d",&val[i]);
    scanf("%lld%lld",&s,&p);
    fo(i,1,p){
        LL x;scanf("%lld",&x);
        save[x]=1;
    }
    tarjan(s);
    gra=0;memset(begin,0,sizeof(begin));
    fo(i,1,m)
        if(bel[u[i]]&&bel[v[i]]&&bel[u[i]]!=bel[v[i]])insert(bel[u[i]],bel[v[i]]),pre[v[i]]++;
    LL l=0,r=0,now;
    st[++r]=s;
    for(;l!=r;){
        now=st[++l];
        for(LL i=begin[now];i;i=next[i]){
            pre[to[i]]--;
            if(!pre[to[i]])inst[st[++r]=to[i]]=1;
        }
    }
    fd(i,r,1){
        now=st[i];
        for(LL i=begin[now];i;i=next[i])
            f[now]=max(f[now],f[to[i]]);
        if(save[now]||f[now])f[now]+=val[now];
    }
    printf("%lld",f[s]);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值