这题有毒。首先显然是差分约束裸题,然而n,m<=1e5,并且有两个数据如下:
1、有负环的大数据。由于spfa判负环是o(nm)的,所以这个点要跑5s。然而这个点存在负的自环,可以直接判掉……
2、1->2->...->n的一条链。若1先入队,则可以一次更新完。否则每次编号较小的点会把所有编号大于它的点都重新更新一次,就卡到了o(n^2)。若一般的边表按1->n加边,入队顺序就是n->1。面向数据地,可以倒着加边,或者按1->n先把所有点入队。
有一个tarjan缩点,拓扑排序的做法,好像没有上述面向数据的问题。
#include<bits/stdc++.h> #define N 100005 using namespace std; int n,m,k,s,t; struct edge{ edge* s; int v,w; }e[N*2],*back=e,*h[N]; void add( int u,int v,int w){ h[u]=&(*back++ =(edge){h[u],v,w}); } int d[N],a[N],z[N]; bool spfa(){ queue<int> q; for(int i=1;i<=n;++i){ q.push(i); d[i]=z[i]=1; } while(q.size()){ int u=q.front(); q.pop(); z[u]=0; for(edge* i=h[u];i;i=i->s) if(d[i->v]<d[u]+i->w){ if(++a[i->v]==n) return 0; d[i->v]=d[u]+i->w; if(!z[i->v]++) q.push(i->v); } } return 1; } int main(){ scanf("%d%d",&n,&m); while(m--){ scanf("%d%d%d",&k,&s,&t); if(k==1){ add(s,t,0); add(t,s,0); } if(k==2) add(s,t,1); if(k==3) add(t,s,0); if(k==4) add(t,s,1); if(k==5) add(s,t,0); } printf("%lld\n", !spfa()?-1 :accumulate(d+1,d+n+1,0ll)); }
时间: 2024-12-29 11:58:44