• P3627 [APIO2009]抢掠计划


    P3627 [APIO2009]抢掠计划

    Tarjan缩点+最短(最长)路

    显然的缩点......

    在缩点时,顺便维护每个强连通分量的总权值

    缩完点按照惯例建个新图

    然后跑一遍spfa最长路,枚举每个有酒吧的点即可

    (但是我为什么会搞dp呢.......)

    dp:81pts

    (这么显然的最长路,为什么会搞dp呢.........)

    怕不是被dp题毒害了(大雾)

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<queue>
    #include<cctype>
    using namespace std;
    template <typename T> inline T min(T &a,T &b) {return a<b ?a:b;}
    template <typename T> inline T max(T &a,T &b) {return a>b ?a:b;}
    template <typename T> inline void read(T &x){
        char c=getchar(); x=0;
        while(!isdigit(c)) c=getchar();
        while(isdigit(c)) x=(x<<3)+(x<<1)+(c^48),c=getchar();
    }
    queue <int> h;
    const int N=1000002;
    int n,m,s,p,dfs_clock,dfn[N],low[N],tot,be[N],_top,st[N];
    int val1[N],cnt,hd[N],nxt[N],ed[N],poi[N];
    int val2[N],cnt2,hd2[N],nxt2[N],ed2[N],poi2[N];
    int d[N]; bool bar1[N],bar2[N],vis[N];
    inline void add(int x,int y){
        nxt[ed[x]]=++cnt; hd[x]= hd[x] ? hd[x]:cnt;
        ed[x]=cnt; poi[cnt]=y;
    }
    inline void add2(int x,int y){
        nxt2[ed2[x]]=++cnt2; hd2[x]= hd2[x] ? hd2[x]:cnt2;
        ed2[x]=cnt2; poi2[cnt2]=y;
    }
    inline void tarjan(int x){
        dfn[x]=low[x]=++dfs_clock; st[++_top]=x;
        for(int i=hd[x];i;i=nxt[i]){
            if(!dfn[poi[i]]) tarjan(poi[i]),low[x]=min(low[x],low[poi[i]]);
            else if(!be[poi[i]]) low[x]=min(low[x],dfn[poi[i]]);
        }
        if(dfn[x]==low[x]){
            be[x]=++tot; val2[tot]=val1[x];
            while(st[_top]!=x) be[st[_top]]=tot,val2[tot]+=val1[st[_top--]]; //维护总权值
            --_top;
        }
    }
    int spfa(){
        h.push(be[s]); vis[be[s]]=1;
        while(!h.empty()){
            int x=h.front(); h.pop(); vis[x]=0;
            for(register int i=hd2[x];i;i=nxt2[i])
                if(d[x]+val2[x]>d[poi2[i]]){ //最长路
                    d[poi2[i]]=d[x]+val2[x];
                    if(!vis[poi2[i]]) h.push(poi2[i]),vis[poi2[i]]=1;
                }
        }int ans=0;
        for(register int i=1;i<=tot;++i) //枚举有酒吧的强连通分量
            if(bar2[i])
                ans=max(ans,d[i]+val2[i]);
        return ans;
    }
    int main(){
        read(n); read(m); int q1,q2;
        for(register int i=1;i<=m;++i) read(q1),read(q2),add(q1,q2);
        for(register int i=1;i<=n;++i) read(val1[i]);
        read(s); read(p);
        for(register int i=1;i<=p;++i) read(q1),bar1[q1]=1;
        for(register int i=1;i<=n;++i) if(!dfn[i]) tarjan(i);
        for(register int i=1;i<=n;++i){
            if(bar1[i]) bar2[be[i]]=1; //给新图做上是否有酒吧的标记
            for(register int j=hd[i];j;j=nxt[j])
                if(be[i]!=be[poi[j]])
                    add2(be[i],be[poi[j]]);
        }printf("%d",spfa());
        return 0;
    }
  • 相关阅读:
    【代码笔记】iOS-点击搜索跳转到另外一个页面
    【代码笔记】iOS-仿安卓,本页出现多个选择项
    【代码笔记】iOS-点击任何处,显示出红色的UIView
    【代码笔记】iOS-点击任何处,出现城市
    【代码笔记】iOS-点击加号增加书架,点击减号减少书架
    【代码笔记】iOS-点击出现选择框
    【代码笔记】iOS-底下滚动,上面标题栏也会跟着变动
    【代码笔记】iOS-等待动画
    【代码笔记】iOS-登陆单例
    【代码笔记】iOS-获得现在的时间
  • 原文地址:https://www.cnblogs.com/kafuuchino/p/9691478.html
Copyright © 2020-2023  润新知