NOIP模拟——列队(差分约束)

传送门

考场想出来了的

但是spfa跑多T了

由于每个联通块不连通

我们可以考虑单独建一个虚点,向所有点连一条0的边

这样就只用跑一次spfa了

这是个奇技淫巧

#include<bits/stdc++.h>
using namespace std;
#define ll long long
inline int read(){
    char ch=getchar();
    int res=0,f=1;
    while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
    while(isdigit(ch))res=(res<<3)+(res<<1)+(ch^48),ch=getchar();
    return res*f;
}
const int N=200005;
const int M=800006;
int adj[N],nxt[M],dis[N],to[M],ans,val[M],m,n,cnt,maxn,p,ver[N],in[N];
bool vis[N];
inline void addedge(int u,int v,int w){
    nxt[++cnt]=adj[u],adj[u]=cnt,to[cnt]=v,val[cnt]=w;
}
queue<int> q;
inline bool spfa(int str){
    while(!q.empty())q.pop();
    q.push(str),vis[str]=1,ver[str]=true;maxn=0;dis[str]=0;
    while(!q.empty()){
        int u=q.front();q.pop();vis[u]=false;
        for(int e=adj[u];e;e=nxt[e]){
            int v=to[e];
            if(dis[u]+val[e]>dis[v]){
                dis[v]=dis[u]+val[e];
                if(dis[v]>maxn)maxn=dis[v],p=v;
                if(!vis[v]){
                    q.push(v);vis[v]=true,ver[v]=true;
                    ++in[v];if(in[v]>n)return false;
                }
            }
        }
    }
    return true;
}
int main(){
    n=read(),m=read();
    for(int i=1;i<=m;++i){
        int u=read(),v=read(),w=read();
        addedge(u,v,w),addedge(v,u,-w);
    }
    for(int i=1;i<=n;i++){
        addedge(n+1,i,0);
    }
    memset(dis,128,sizeof(dis));
    if(spfa(n+1)==false){
        cout<<"impossible"<<'\n';
        return 0;
    }
    cout<<maxn;
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_42555009/article/details/83754136