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* */
二分条件:单调性
一切可以得知最优解方向的,也都可以二分