hszxoj ATM [tarjan]

hszxoj ATM

  • 题目描述:\(Siruseri\) 城中的道路都是单向的。不同的道路由路口连接。按照法律的规定, 在每个路口都设立了一个 \(Siruseri\) 银行的 \(ATM\) 取款机。令人奇怪的是,\(Siruseri\) 的酒吧也都设在路口,虽然并不是每个路口都设有酒吧。\(Bandit ji\) 计划实施 \(Siruseri\) 有史以来最惊天动地的 \(ATM\) 抢劫。他将从市中心 出发,沿着单向道路行驶,抢劫所有他 途径的 \(ATM\) 机,最终他将在一个酒吧庆 祝他的胜利。使用高超的黑客技术,他获知了每个 \(ATM\) 机中可以掠取的 现金数额。他希望你帮助他计算从市中心出发最后到达某个酒吧时最多能抢劫的现金总数。他可 以经过同一路口 或道路任意多次。但只要他抢劫过某个 \(ATM\) 机后,该 \(ATM\) 机 里面就不会再有钱了。 例如,假设该城中有 \(6\) 个 路口,道路的连接情况如下图所示

    市中心在路口 \(1\) ,由一个入口符号→来标识,那些有酒吧的路口用双圈来表示。每个 \(ATM\) 机中可取的钱数标在了路口的上方。在这个例子中,\(Banditji\) 能抢 劫的现金总数为 \(47\) ,实施的抢劫路线是: \(1-2-4-1-2-3-5\)
  • 输入格式: 第一行包含两个整数 \(N\)\(M\)\(N\) 表示路口的个数, \(M\) 表示道路条数。 接下来 \(M\) 行,每行两个整数,这两个整数都在 \(1\)\(N\) 之间, 第 \(i+1\) 行的两个整数表示第 \(i\) 条道路的起点和终点的路口编号。 接下来 \(N\) 行,每行一个整数,按顺序表示每个路口处的 \(ATM\) 机中的钱数。 接下来一行包含两个整数 \(S\)\(P\)\(S\) 表示市中心的编号,也就是出发的路口。 \(P\) 表示酒吧数目。 接下来的一行中有 \(P\) 个整数,表示 \(P\) 个有酒吧的路口的编号 \(N, M<=500000\) 。每个 \(ATM\) 机中可取的钱数为一个非负整数且不超过 \(4000\) 。 输入数据保证你可以从市中心沿着 \(Siruseri\) 的单向的道路到达其中的至少一个酒吧。
  • 输出格式:输出一个整数,表示 \(Banditji\) 从市中心开始到某个酒吧结束所能抢劫的最多的现金总数。

可以想到 \(spfa\) 跑最长路 \(\Large{but}\) \(\Large{N,M<=500000}\) 且 只要他抢劫过某个 ATM 机后,该 ATM 机 里面就不会再有钱了

这就比较该死,直接 \(spfa\) 一定会超时,且没办法搞这个不能反复取钱,所以就用到 \(\large{tarjan缩点}\)

输入的时候存了一下这个from和to,为的是缩完点后再次建图时的判断,如果该条路上起点和终点在一个连通块里,自然就不需要把他们俩再连起来了

for(int i=1;i<=m;i++)
        if(color[from[i]]!=color[to[i]])
            e[color[from[i]]].push_back(color[to[i]]);

于是谈到了再次建图,用 &tarjan$ 缩完点后,建一遍缩完点的图,再跑 \(spfa\) 就不会超时了

我这里没有建两个图,缩完点后之前的图就没用了,吧之前的图初始化掉再建一遍新的图就好了

memset(e,0,sizeof(e));
    for(int i=1;i<=m;i++)
        if(color[from[i]]!=color[to[i]])
            e[color[from[i]]].push_back(color[to[i]]);

观察输入可以发现他讲出发点和结束点给了,出发点就是 \(s\) ,结束点就是那几个酒吧 \(bar\) ,讲这几个酒吧中获利最大的那个输出就是了

然后发现这个玩意在跑 \(tarjan\) 缩点的时候根本用不到,所以不妨在跑完 \(tarjan\) 之后再把这些东西输入,就会方便很多,不然要是一开始就输入的话就需要记录这些点,然后在算 \(spfa\) 的时候还需要给他一个判断是不是酒吧的点,就很麻烦

像这样

for(i=1;i<=pos;++i)ls=read(),club[ls]=1;
if(club[z])win[tot]=1;
for(i=1;i<=tot;++i)if(win[i])ansss=max(ansss,dis[i]);

但是如果把他在后面输入,就可以只

for(int i=1;i<=p;i++) read(bar),ans=max(ans,d[color[bar]]);

全部代码

#include<bits/stdc++.h>
#define int long long
#define endl "\n"
using namespace std;
const int N=500001;
template<typename Tp> inline void read(Tp&x)
{
    x=0;register bool f=1;
    register char c=getchar();
    for(;c<'0'||c>'9';c=getchar()) if(c=='-') f=0;
    for(;'0'<=c&&c<='9';c=getchar()) x=(x<<1)+(x<<3)+(c^48);
    x=(f?x:~x+1);
}
vector<int>e[N];
stack<int>sta;
queue<int> q;
int n,m,s,p,bar,ans,sccnt,tot;
int from[N],to[N],w[N],dfn[N],low[N],color[N],siz[N],d[N];
bool v[N],ins[N];
void tarjan(int x)
{
    dfn[x]=low[x]=++tot;
    sta.push(x),ins[x]=1;
    for(int y:e[x])
    {      
        if(!dfn[y]) tarjan(y),low[x]=min(low[x],low[y]);
        else if(ins[y]) low[x]=min(low[x],dfn[y]);
    }
    if(dfn[x]==low[x])
    {
        int y;++sccnt;
        while(y!=x)
            y=sta.top(),
            sta.pop(), 
            ins[y]=0,
            color[y]=sccnt,
            siz[sccnt]+=w[y];
    }
}
void spfa(int s)
{
    q.push(s);
    d[s]=siz[s];
    v[s]=1;
    while(!q.empty())
    {
        int x=q.front();
        q.pop();
        v[x]=0;
        for(int y:e[x])
        {
            if(d[y]<d[x]+siz[y])
            {
                d[y]=d[x]+siz[y];
                if(!v[y]) q.push(y),v[y]=1;
            }
        }
    }
}
signed main()
{
    #ifndef ONLINE_JUDGE
    freopen("in.txt","r",stdin);
    freopen("out.txt","w",stdout);
    #endif
    read(n),read(m);
    for(int i=1;i<=m;i++) 
        read(from[i]),read(to[i]),
        e[from[i]].push_back(to[i]);
    for(int i=1;i<=n;i++) read(w[i]);
    for(int i=1;i<=n;i++) if(!dfn[i]) tarjan(i);
    memset(e,0,sizeof(e));
    for(int i=1;i<=m;i++)
        if(color[from[i]]!=color[to[i]])
            e[color[from[i]]].push_back(color[to[i]]);
    read(s),read(p);
    spfa(color[s]);
    for(int i=1;i<=p;i++) read(bar),ans=max(ans,d[color[bar]]);
    cout<<ans;
}

但是离谱的是,把小于号改成大于号也对,跑最短路也对了???,

\(\huge\color{a7e747}{太水了这个数据}\)

memset(d,0x3f,sizeof(d));
    q.push(s);
    d[s]=siz[s];
    v[s]=1;
    while(!q.empty())
    {
        int x=q.front();
        q.pop();
        v[x]=0;
        for(int y:e[x])
        {
            if(d[y]>d[x]+siz[y])
            {
                d[y]=d[x]+siz[y];
                if(!v[y]) q.push(y),v[y]=1;
            }
        }
    }

不要手残 \(\Huge\color{3fdfaf}{qwq}\)

posted @ 2023-11-25 19:39  卡布叻_周深  阅读(53)  评论(0编辑  收藏  举报