是时候再写一篇新的博客了

BZOJ 2330&Luogu 3275 糖果

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

每个限制为三个整数: X, A, B。

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

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

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

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

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

建图:

对于x=1的情况,由A向B建一条长度为0的边,并且由B向A建一条长度为0的边。

对于x=2的情况,由A向B建一条长度为1的边,表示B比A至少多一个糖果。

对于x=3的情况,由B向A建一条长度为0的边,(由糖果数少的指向多的)。

对于x=4的情况,由B向A建一条长度为1的边,表示A比B至少多一个糖果。

对于x=5的情况,由A向B建一条长度为0的边,(由糖果数少的指向多的)。

建一个超级原点0(用超级原点来限制 糖果数>=1),从超级原点向每个点连一条长度为1的边。

从超级原点出发跑==最长路,判断是否有环=>无解

判断连边顺序:考虑最长路dis[v]>=dis[u]+w;

易见每种限制都可以表示为差分约束形式的不等式。

然后这道题跑单源最长路也是很迷惑对吧√

画个图理解(李姐)一下(盗的)

你看介个图,如果跑最短路,1号点的dis=1,但显而易见,1号点的答案应该是2才是合法的,因此我们需要跑最长路,才能满足所有的约束条件。

对于情况2和情况4,如果出现了a>a或者a<a的情况,显然是无解的。

然后spfa判环,如果有一个点进入队列n-1次,就有环了?然后无解输出。

最后,记录答案的变量要记得开 long long

#include<bits/stdc++.h>

using namespace std;

inline int read(){
	int ans=0;
	char last=' ',ch=getchar();
	while(ch>'9'||ch<'0') last=ch,ch=getchar();
	while(ch>='0'&&ch<='9') ans=(ans<<1)+(ans<<3)+ch-'0',ch=getchar();
	if(last=='-') ans=-ans;
	return ans;
}
const int mxm=300010;
const int mxn=300010;

int n,k;
int head[mxn],ecnt;
struct node{
	int to,dis,nxt;
}e[mxm<<1];

void add(int from,int to,int dis){
	++ecnt;
	e[ecnt].to=to;
	e[ecnt].dis=dis;
	e[ecnt].nxt=head[from];
	head[from]=ecnt;
}

queue<int> q;
bool bj,vis[mxn];
long long dis[mxn],cnt[mxn];
void spfa(int s){
	q.push(s);
	vis[s]=1;
	
	while(!q.empty()){
		int u=q.front();
		q.pop();
		vis[u]=0;
		if(cnt[u]==n-1){
			bj=1;
			return;
		}
		cnt[u]++;
		for(int i=head[u],v,w;i;i=e[i].nxt){
			v=e[i].to;w=e[i].dis;
			if(dis[v]<dis[u]+w){
				dis[v]=dis[u]+w;
				if(!vis[v]) {
					q.push(v);
					vis[v]=1;
				}
			}
		}
	}
}

long long ans;

int main(){
	int x,a,b;
	n=read();k=read();
	for(int i=1;i<=k;i++){
		x=read();a=read();b=read();
		if(x==1) {
			add(a,b,0);
			add(b,a,0);
		}
		if(x==2) {
			if(a==b) {
				printf("-1");
				return 0;
			}
			add(a,b,1);
		}
		if(x==3)
			add(b,a,0);
		if(x==4) {
			if(a==b) {
				printf("-1");
				return 0;
			}
			add(b,a,1);
		}
		if(x==5)
			add(a,b,0);
	}
	for(int i=n;i>=1;i--) add(0,i,1);
	spfa(0);
	if(bj){
		printf("-1");
		return 0;
	}
	for(int i=1;i<=n;i++) {
		if(dis[i]==0) {
			printf("-1");
			return 0;
		}
		ans+=dis[i];
	}
	printf("%lld",ans);
	return 0;
}
原文地址:https://www.cnblogs.com/zhuier-xquan/p/11402360.html