题目
题解
裸的差分约束......
也许是因为太裸了,用(sàng)心(xīn)良(bìng)苦(kuáng)的出题人竟然卡spfa,某数据点有一条长为十万的链……
倒着连边
代码
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <queue>
#define N 500050
#define inf 10000000000
#define ll long long
using namespace std;
int n,k;
ll ans;
int num,a[N],b[N],w[N],nt[N],p[N];
void add(int x,int y,int v)
{
a[++num]=x;b[num]=y;w[num]=v;
nt[num]=p[x];p[x]=num;
}
int flag[N],cnt[N],f;queue<int> q;ll dis[N];
void spfa()
{
for(int i=1;i<=n;i++) dis[i]=-inf;
q.push(0);flag[0]=1;dis[0]=0;cnt[0]++;
while(!q.empty())
{
int k=q.front();q.pop();
for(int e=p[k];e;e=nt[e])
{
int kk=b[e];
if(dis[kk]<dis[k]+w[e])
{
dis[kk]=dis[k]+w[e];
if(!flag[kk]) {flag[kk]=1;q.push(kk);cnt[kk]++;}
if(cnt[kk]>n) {f=1;break;}
}
}
flag[k]=0;
if(f) break;
}
}
int main()
{
scanf("%d%d",&n,&k);
for(int i=1;i<=k;i++)
{
int opt,x,y;scanf("%d%d%d",&opt,&x,&y);
if(opt==1) add(x,y,0),add(y,x,0);
else if(opt==2) {if(x==y){printf("-1");return 0;}add(x,y,1);}
else if(opt==3) add(y,x,0);
else if(opt==4) {if(x==y){printf("-1");return 0;}add(y,x,1);}
else add(x,y,0);
}
for(int i=n;i>=1;i--) add(0,i,1);
spfa();
if(f) printf("-1");
else
{
for(int i=1;i<=n;i++) ans+=dis[i];
printf("%lld",ans);
}
return 0;
}