51nod1340地铁环线

经典题。

经典差分约束模型。

但是

显然这个总长是有上下界的。

直接二分总长,判断有没有负环

如果没有负环好办,有负环就不知道怎么偏了。

因为没有单调性

(如果所有没有单调性的函数图像,都知道往哪里走更优,

岂不是全都可以二分了

但是本题特殊在于,至少还是个区间!

二分左右端点。

负环记录k*mid+b的k,根据k的正负就可以知道哪个方向可能有解。

任意一个负环都可以判断的。

#include<bits/stdc++.h>
#define reg register int
#define il inline
#define fi first
#define se second
#define mk(a,b) make_pair(a,b)
#define numb (ch^'0')
#define pb push_back
#define solid const auto &
#define enter cout<<endl
#define pii pair<int,int>
using namespace std;
// #define int long long 
typedef long long ll;
template<class T>il void rd(T &x){
    char ch;x=0;bool fl=false;while(!isdigit(ch=getchar()))(ch=='-')&&(fl=true);
    for(x=numb;isdigit(ch=getchar());x=x*10+numb);(fl==true)&&(x=-x);}
template<class T>il void output(T x){if(x/10)output(x/10);putchar(x%10+'0');}
template<class T>il void ot(T x){if(x<0) putchar('-'),x=-x;output(x);putchar(' ');}
template<class T>il void prt(T a[],int st,int nd){for(reg i=st;i<=nd;++i) ot(a[i]);putchar('\n');}
namespace Modulo{
const int mod=998244353;
il int ad(int x,int y){return x+y>=mod?x+y-mod:x+y;}
il int sub(int x,int y){return ad(x,mod-y);}
il int mul(int x,int y){return (ll)x*y%mod;}
il void inc(int &x,int y){x=ad(x,y);}
il void inc2(int &x,int y){x=mul(x,y);}
il int qm(int x,int y=mod-2){int ret=1;while(y){if(y&1) ret=mul(x,ret);x=mul(x,x);y>>=1;}return ret;}
template<class ...Args>il int ad(const int a,const int b,const Args &...args) {return ad(ad(a,b),args...);}
template<class ...Args>il int mul(const int a,const int b,const Args &...args) {return mul(mul(a,b),args...);}
}
// using namespace Modulo;
namespace Miracle{
const int N=55;
const ll inf=1e9+1;
int n,m1,m2;
struct node{
    int fr,nxt,to;
    int k,b;
    ll val(ll x){
        return (ll)k*x+b;
    }
}e[N*N];
int hd[N],cnt;
void add(int x,int y,int k,int b){
    // cout<<" add "<<x<<" to "<<y<<" k "<<k<<" b "<<b<<endl;
    e[++cnt].nxt=hd[x];
    e[cnt].to=y;e[cnt].k=k;e[cnt].b=b;
    e[cnt].fr=x;
    hd[x]=cnt;
}
ll dis[N],pre[N];
int has[N];
bool vis[N];
queue<int>q;
int spfa(ll mid){
    memset(dis,0x3f,sizeof dis);
    dis[0]=0;
    memset(vis,0,sizeof vis);
    while(!q.empty()) q.pop();
    has[0]=1;
    q.push(0);
    while(!q.empty()){
        int x=q.front();q.pop();vis[x]=0;
        for(reg i=hd[x];i;i=e[i].nxt){
            int y=e[i].to;
            if(dis[y]>dis[x]+e[i].val(mid)){
                dis[y]=dis[x]+e[i].val(mid);
                pre[y]=i;
                has[y]=has[x]+1;
                if(has[y]==n+1){
                    int z=y;
                    memset(vis,0,sizeof vis);
                    do{
                        vis[z]=1;
                        z=e[pre[z]].fr;
                    }while(!vis[z]);
                    int k=0;
                    int lp=z;
                    do{
                        k+=e[pre[z]].k;
                        z=e[pre[z]].fr;
                    }while(z!=lp);

                    if(k>0){
                        return 1;
                    }else return -1;
                }

                if(!vis[y]){
                    vis[y]=1;
                    q.push(y);
                }
            }
        }
    }
    return 0;
}
void clear(){
    memset(hd,0,sizeof hd);cnt=0;
}
int main(){
    // rd(n);rd(m);
    int T;
    rd(T);
    while(T--){
        clear();
        rd(n);rd(m1);rd(m2);
        for(reg i=1;i<n;++i){
            add(i,i-1,0,-1);
        }
        add(0,n-1,1,-1);
        int a,b,c;
        for(reg i=1;i<=m1;++i){
            rd(a);rd(b);rd(c);
            if(a<b){
                add(b,a,0,-c);
            }else{
                add(b,a,1,-c);
            }
        }
        for(reg i=1;i<=m2;++i){
            rd(a);rd(b);rd(c);
            if(a<b){
                add(a,b,0,c);
            }else{
                add(a,b,-1,c);
            }
        }
        ll L=n,R=(ll)n*inf;
        ll al=R+1;
        while(L<=R){
            ll mid=(L+R)>>1;
            int lp=spfa(mid);
            if(lp==-1){
                R=mid-1;
            }else if(lp==1){
                L=mid+1;
            }else{
                al=mid;R=mid-1;
            }
        }
        L=n,R=(ll)n*inf;
        ll ar=n-1;
        while(L<=R){
            ll mid=(L+R)>>1;
            int lp=spfa(mid);
            if(lp==-1){
                R=mid-1;
            }else if(lp==1){
                L=mid+1;
            }else{
                ar=mid;L=mid+1;
            }
        }
        // cout<<" al "<<al<<" ar "<<ar<<endl;
        if(ar<al){
            puts("0");
        }else if(ar==(ll)n*inf){
            puts("-1");
        }else{
            printf("%lld\n",ar-al+1);
        }
    }
    return 0;
}

}
signed main(){
    Miracle::main();
    return 0;
}

/*
   Author: *Miracle*
*/

二分条件:单调性

一切可以得知最优解方向的,也都可以二分

转载于:https://www.cnblogs.com/Miracevin/p/11040320.html

猜你喜欢

转载自blog.csdn.net/weixin_33924770/article/details/93207857
今日推荐