[SCOI2011]糖果

题目

bzoj2330

题解

裸的差分约束......

也许是因为太裸了,用(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;
}
原文地址:https://www.cnblogs.com/XYZinc/p/7417158.html