【题解】LuoGu3275:[SCOI2011]糖果

原题传送门
差分约束
考虑如何连边,建立一个超级源点0
a d d e d g e ( 0 , i , 1 ) addedge(0,i,1)
对于接下来的关系

  • o p t = 1 , a d d e d g e ( x , y , 0 ) , a d d e d g e ( y , x , 0 ) opt=1,addedge(x, y, 0),addedge(y,x,0)
  • o p t = 2 , a d d e d g e ( x , y , 1 ) opt=2,addedge(x,y,1)
  • o p t = 3 , a d d e d g e ( y , x , 0 ) opt=3,addedge(y,x,0)
  • o p t = 4 , a d d e d g e ( y , x , 1 ) opt=4,addedge(y,x,1)
  • o p t = 5 , a d d e d g e ( x , y , 0 ) opt=5,addedge(x,y,0)

然后用 s p f a spfa 跑最长路
最终 a n s = s u m i = 1 n d i s i ans=sum_{i=1}^{n}dis_i

Code:

#include <bits/stdc++.h>
#define maxn 200010
#define LL long long
using namespace std;
struct Edge{
	int to, next, len;
}edge[maxn << 1];
int num, head[maxn], n, m, dis[maxn], vis[maxn], tot[maxn];
queue <int> q;

inline int read(){
	int s = 0, w = 1;
	char c = getchar();
	for (; !isdigit(c); c = getchar()) if (c == '-') w = -1;
	for (; isdigit(c); c = getchar()) s = (s << 1) + (s << 3) + (c ^ 48);
	return s * w;
}

void addedge(int x, int y, int z){ edge[++num] = (Edge){y, head[x], z}, head[x] = num; }

int main(){
	n = read(), m = read();
	while (m--){
		int opt = read(), x = read(), y = read();
		if ((opt == 2 || opt == 4) && x == y) return puts("-1"), 0;
		if (opt == 1) addedge(x, y, 0), addedge(y, x, 0);
		else if (opt == 2) addedge(x, y, 1);
		else if (opt == 3) addedge(y, x, 0);
		else if (opt == 4) addedge(y, x, 1);
		else addedge(x, y, 0);
	}
	for (int i = n; i; --i) addedge(0, i, 1);
	vis[0] = 1;
	q.push(0);
	while (!q.empty()){
		int u = q.front(); q.pop();
		if ((++tot[u]) > n) return puts("-1"), 0;
		vis[u] = 0;
		for (int i = head[u]; i; i = edge[i].next){
			int v = edge[i].to;
			if (dis[v] < dis[u] + edge[i].len){
				dis[v] = dis[u] + edge[i].len;
				if (!vis[v]) vis[v] = 1, q.push(v);
			}
		}
	}
	LL ans = 0;
	for (int i = 1; i <= n; ++i) ans += dis[i];
	printf("%lld\n", ans);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/ModestCoder_/article/details/108201380
今日推荐