• 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('
    ');}
    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
    ",ar-al+1);
            }
        }
        return 0;
    }
    
    }
    signed main(){
        Miracle::main();
        return 0;
    }
    
    /*
       Author: *Miracle*
    */

    二分条件:单调性

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

  • 相关阅读:
    MySQL必知必会(数据分组,Group by和Having子句, Select子句的顺序)
    MySQL必知必会(汇总数据, 聚集函数)
    MySQL必知必会(使用函数处理数据)
    菜根谭#206
    菜根谭#205
    菜根谭#204
    菜根谭#203
    菜根谭#202
    菜根谭#201
    菜根谭#200
  • 原文地址:https://www.cnblogs.com/Miracevin/p/11040320.html
Copyright © 2020-2023  润新知