BZOJ1202 [HNOI2005]狡猾的商人 spfa
欢迎访问~原文出处——博客园-zhouzhendong
去博客园看该题解
题目传送门 - BZOJ1202
题意概括
有一个数列,共n个数字。
告诉你m个区间和,问是否矛盾。
数据组数<=100, n<=100, m<=1000
题解
网上都说的并查集的,貌似挺快的。
我这里给出一个特殊的做法,复杂度O(T(m+n)),T为数据组数。
我们根据题目给出的信息建图,然后spfa判断。
对于输入的 a,b,c,我们建立(a,b+1,c)(b+1,a,-c)两条边。
如果一个点,之前已经被某一个点更新过一次,现在又被某一个点更新了,那么就矛盾了。
所以,每一个点只会被更新一次,每一条边也最多访问一次,所以复杂度是可以的。
但是不知道为什么跑了244MS……
代码
#include <cstring> #include <algorithm> #include <cstdio> #include <cstdlib> #include <cmath> using namespace std; const int N=100+5,M=2000+5; struct Gragh{ int cnt,x[M],y[M],z[M],nxt[M],fst[N]; void set(){ cnt=0; memset(fst,0,sizeof fst); } void add(int a,int b,int c){ x[++cnt]=a,y[cnt]=b,z[cnt]=c; nxt[cnt]=fst[a],fst[a]=cnt; } }g; int T,n,m,dis[N],vis[N],q[N],head,tail,qmod; bool check(){ int x,y,z; memset(dis,0,sizeof dis); memset(vis,0,sizeof vis); qmod=n+2; for (int mon=1;mon<=n;mon++){ if (vis[mon]) continue; head=tail=0; q[tail=(tail+1)%qmod]=mon; vis[mon]=1; while (head!=tail){ x=q[head=(head+1)%qmod]; for (int i=g.fst[x];i;i=g.nxt[i]){ y=g.y[i],z=g.z[i]; if (!vis[y]){ vis[y]=1; dis[y]=dis[x]+z; q[tail=(tail+1)%qmod]=y; continue; } if (dis[y]!=dis[x]+z) return 0; } } } return 1; } int main(){ scanf("%d",&T); while (T--){ scanf("%d%d",&n,&m); g.set(); for (int i=1,a,b,c;i<=m;i++){ scanf("%d%d%d",&a,&b,&c); if (a>b) swap(a,b); g.add(a,b+1,c); g.add(b+1,a,-c); } puts(check()?"true":"false"); } return 0; }