BZOJ 2330: [SCOI2011]糖果

Description

幼儿园里有N个小朋友,lxhgww老师现在想要给这些小朋友们分配糖果,要求每个小朋友都要分到糖果。但是小朋友们也有嫉妒心,总是会提出一些要求,比如小明不希望小红分到的糖果比他的多,于是在分配糖果的时候,lxhgww需要满足小朋友们的K个要求。幼儿园的糖果总是有限的,lxhgww想知道他至少需要准备多少个糖果,才能使得每个小朋友都能够分到糖果,并且满足小朋友们所有的要求。

Input

输入的第一行是两个整数NK

接下来K行,表示这些点需要满足的关系,每行3个数字,XAB

如果X=1, 表示第A个小朋友分到的糖果必须和第B个小朋友分到的糖果一样多;

如果X=2, 表示第A个小朋友分到的糖果必须少于第B个小朋友分到的糖果

如果X=3, 表示第A个小朋友分到的糖果必须不少于第B个小朋友分到的糖果

如果X=4, 表示第A个小朋友分到的糖果必须多于第B个小朋友分到的糖果

如果X=5, 表示第A个小朋友分到的糖果必须不多于第B个小朋友分到的糖果;

Output

输出一行,表示lxhgww老师至少需要准备的糖果数,如果不能满足小朋友们的所有要求,就输出-1

Sample Input

5 7

1 1 2

2 3 2

4 4 1

3 4 5

5 4 5

2 3 5

4 5 1

Sample Output


11

HINT

【数据范围】


    对于30%的数据,保证 N<=100


    对于100%的数据,保证 N<=100000


对于所有的数据,保证 K<=100000,1<=X<=5,1<=A, B<=N

题解

查分约束系统经典题。有一个坑爹的点,形成的是十万个点的一条链,如果从0到所有点顺序加边就会T,改成倒序就A了

#include<cstdio>
#include<cstring>
#include<iostream>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#define inf 1<<30
#define ll long long
using namespace std;
int n,m,tag,head[100002],zz;
struct bian{int to,nx,v;} e[500002];
int q[100002],dis[100002],pd[100002],ct[100002];
ll ans;
void insert(int x,int y,int z)
{
	zz++; e[zz].to=y; e[zz].v=z; e[zz].nx=head[x]; head[x]=zz;
}
void init()
{
	scanf("%d%d",&n,&m);
	int i,x,y,z;
	for(i=1;i<=m;i++)
	   {scanf("%d%d%d",&x,&y,&z);
	    if(x==1) {insert(y,z,0); insert(z,y,0);}
	    else if(x==2)
	       {if(y==z) {printf("-1\n"); tag=1; return;}
	        insert(y,z,1);
		   }
		else if(x==3) insert(z,y,0);
		else if(x==4)
		   {if(y==z) {printf("-1\n"); tag=1; return;}
		    insert(z,y,1);
		   }
		else insert(y,z,0);
	   }
	for(i=n;i>0;i--) insert(0,i,1);
}
bool spfa()
{
	int i,t=0,w=1,p,x;
	//for(i=0;i<=n;i++) dis[i]=-inf;
	dis[0]=0; pd[0]=1; q[0]=0; ct[0]=1;
	while(t!=w)
	   {x=q[t];
	    t=(t+1)%100002;
	    for(i=head[x];i;i=e[i].nx)
	       {p=e[i].to;
			if(dis[x]+e[i].v>dis[p])
			   {dis[p]=dis[x]+e[i].v;
			    ct[p]++;
				if(ct[p]>=n) return false;
				if(!pd[p])
				   {q[w]=p; pd[p]=1; w=(w+1)%100002;}
			   }
		   }
		pd[x]=0;
	   }
	return true;
}
int main()
{
	init();
	if(tag==1) return 0;
	if(!spfa()) {printf("-1\n"); return 0;}
	int i;
	for(i=1;i<=n;i++) ans+=dis[i];
	printf("%lld\n",ans);
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值