差分约束
差分约束学了就没用过。。。现在忘光了
貌似这道题可以Tarjan+拓扑过,但是我不会
其实这道题是很裸的差分约束了。我们来分析一下这五种关系:
1:建
x
x
和的权值为
0
0
的双向边。
2:建到
y
y
的权值为的单向边。注意当
x=y
x
=
y
时判掉
3:建
y
y
到的权值为
0
0
的单项边。
4:建到
x
x
的权值为的单项边。注意当
x=y
x
=
y
时判掉
5:建
x
x
到的权值为
0
0
的单项边。
然后spfa跑最长路即可。
然而出题人出了一条链。。。那么一开始就把所有点加进去就行了。
注意判环,答案爆
代码:
#include<queue>
#include<cctype>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 100005
#define F inline
using namespace std;
typedef long long LL;
struct edge{ int nxt,to,d; }ed[N<<2];
int n,m,k,h[N],t[N],d[N];
LL ans; bool f[N];
queue <int> q;
F char readc(){
static char buf[100000],*l=buf,*r=buf;
if (l==r) r=(l=buf)+fread(buf,1,100000,stdin);
return l==r?EOF:*l++;
}
F int _read(){
int x=0; char ch=readc();
while (!isdigit(ch)) ch=readc();
while (isdigit(ch)) x=(x<<3)+(x<<1)+(ch^48),ch=readc();
return x;
}
#define addedge(x,y,z) (ed[++k]=(edge){h[x],y,z},h[x]=k)
F bool spfa(){
while (!q.empty()){
int x=q.front(); f[x]=false,q.pop();
for (int i=h[x],v;i;i=ed[i].nxt)
if (d[x]+ed[i].d>d[v=ed[i].to]){
d[v]=d[x]+ed[i].d;
if (++t[v]>=n) return false;
if (!f[v]) q.push(v),f[v]=true;
}
}
return true;
}
int main(){
n=_read(),m=_read();
for (int i=1;i<=m;i++){
int f=_read(),x=_read(),y=_read();
switch(f){
case 1: addedge(x,y,0),addedge(y,x,0); break;
case 3: addedge(y,x,0); break;
case 5: addedge(x,y,0); break;
default:
if (x==y) return puts("-1"),0;
f==2?addedge(x,y,1):addedge(y,x,1); break;
}
}
for (int i=1;i<=n;i++) d[i]=t[i]=f[i]=true,q.push(i);
if (!spfa()) return puts("-1"),0;
for (int i=1;i<=n;i++) ans+=d[i];
return printf("%lld\n",ans),0;
}