题面:Luogu2294 BZOJ1202
带权并查集直接做
路径压缩的时候把并查集的权值算好,最后判断矛盾是只要前缀减一下就好了
还有一种做法是差分约束,暴力按照题意建边然后spfa判负环即可
luogu实测两者的速度都在130ms左右,差距不大
并查集:
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<iostream>
#include<cstdlib>
#include<set>
#include<map>
#include<string>
#include<ctime>
#include<queue>
#include<vector>
using namespace std;
int n,m,fa[100001],v[100001];
inline int getfather(int x){
if(fa[x]==x)return x;
int t=getfather(fa[x]);
v[x]+=v[fa[x]];return fa[x]=t;
}
int main()
{
int T;scanf("%d",&T);
while(T--){
bool flag=0;
scanf("%d%d",&n,&m);
for(int i=0;i<=n;i++)fa[i]=i,v[i]=0;
for(int i=1;i<=m;i++){
int x,y,z;scanf("%d%d%d",&x,&y,&z);x--;
int fx=getfather(x),fy=getfather(y);
if(fx!=fy){
fa[fx]=fy;v[fx]=v[y]-v[x]-z;
}else if(v[y]-v[x]!=z){flag=1;break;}
}
puts(flag?"false":"true");
}
return 0;
}
差分约束:
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<iostream>
#include<cstdlib>
#include<set>
#include<map>
#include<string>
#include<ctime>
#include<queue>
#include<vector>
using namespace std;
bool vis[1001];
int n,m,dist[2001];
int nedge=0,p[2001],c[2001],nex[2001],head[2001];
inline void addedge(int x,int y,int z){
p[++nedge]=y;c[nedge]=z;
nex[nedge]=head[x];head[x]=nedge;
}
inline bool spfa(int x){
vis[x]=1;
for(int k=head[x];k;k=nex[k])if(dist[p[k]]>dist[x]+c[k]){
dist[p[k]]=dist[x]+c[k];
if(vis[p[k]]||!spfa(p[k]))return 0;
}
vis[x]=0;return 1;
}
int main()
{
int T;scanf("%d",&T);
while(T--){
scanf("%d%d",&n,&m);
nedge=0;memset(p,0,sizeof p);memset(c,0,sizeof c);
memset(nex,0,sizeof nex);memset(head,0,sizeof head);
for(int i=1;i<=m;i++){
int x,y,z;scanf("%d%d%d",&x,&y,&z);
addedge(x-1,y,z);addedge(y,x-1,-z);
}
for(int i=0;i<=n;i++)dist[i]=1e9;
memset(vis,0,sizeof vis);dist[0]=0;
puts(spfa(0)?"true":"false");
}
return 0;
}