#Tarjan,SPFA,差分約束系統#BZOJ 2330 AcWing 368 銀河
阿新 • • 發佈:2020-11-04
分析
首先這明顯是一道差分約束題,但是無解的情況確實比較噁心,
考慮它的邊權為0或1,無解當且僅當某個強連通分量內的邊至少一條邊邊權為1,
那麼用有向圖的Tarjan縮點後跑SPFA就可以了
程式碼
#include <cstdio> #include <cctype> #include <stack> #include <cstring> #include <queue> #define rr register using namespace std; const int N=100011; stack<int>stac; queue<int>q; struct node{int y,w,next;}e[N*3],E[N*3]; int dfn[N],low[N],v[N],dis[N],hs[N],col[N]; int siz[N],as[N],cnt,tot,et,Et,n,m; long long ans; inline signed iut(){ rr int ans=0; rr char c=getchar(); while (!isdigit(c)) c=getchar(); while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar(); return ans; } inline void add(int x,int y,int w){E[++Et]=(node){y,w,hs[x]},hs[x]=Et;} inline signed min(int a,int b){return a<b?a:b;} inline void tarjan(int x){ dfn[x]=low[x]=++tot, stac.push(x),v[x]=1; for (rr int i=hs[x];i;i=E[i].next) if (!dfn[E[i].y]){ tarjan(E[i].y); low[x]=min(low[x],low[E[i].y]); }else if (v[E[i].y]) low[x]=min(low[x],dfn[E[i].y]); if (dfn[x]==low[x]){ rr int y; ++cnt; do{ y=stac.top(); stac.pop(); col[y]=cnt,v[y]=0,++siz[cnt]; }while (x^y); } } signed main(){ n=iut()+1; m=iut(); for (rr int i=1;i<n;++i) add(n,i,1); for (rr int i=1;i<=m;++i){ rr int z=iut(),x=iut(),y=iut(); switch (z){ case 1:{ add(x,y,0),add(y,x,0); break; } case 2:{ add(x,y,1); break; } case 3:{ add(y,x,0); break; } case 4:{ add(y,x,1); break; } case 5:{ add(x,y,0); break; } } } for (rr int i=1;i<=n;++i) if (!dfn[i]) tarjan(i); for (rr int i=1;i<=n;++i) for (rr int j=hs[i];j;j=E[j].next) if (col[i]^col[E[j].y]) e[++et]=(node){col[E[j].y],E[j].w,as[col[i]]},as[col[i]]=et; else if (E[j].w) return !printf("-1"); memset(dis,0xcf,sizeof(dis)); q.push(col[n]),v[col[n]]=1,dis[col[n]]=0; while (!q.empty()){ rr int x=q.front(); q.pop(); for (rr int i=as[x];i;i=e[i].next) if (dis[e[i].y]<dis[x]+e[i].w){ dis[e[i].y]=dis[x]+e[i].w; if (!v[e[i].y]) v[e[i].y]=1,q.push(e[i].y); } v[x]=0; } for (rr int i=1;i<=cnt;++i) ans+=siz[i]*dis[i]; return !printf("%lld",ans); }