BZOJ2330&&洛谷P3275

裸的查分约束,通过它给的条件,可以推出,i比k少,那么建一条i->k的cost=1的边,反之亦然,若i<=k,则建一条i->k,cost=0的边,反之亦然,若相等,则双向建cost=0的边,然后从0号点向每个点点建cost=1的边,然后跑一下最长路,然后累加每一个的dis,因为查分约束问题中存在环无解问题,所以要判断是否存在环

然后就是网上说的从0正逆向向每个点建边防止10W的链的问题,我正向建边,从1->n,没有T ,emmmm

代码

#include<cmath>
#include<queue>
#include<cstdio>
#include<vector>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int M=400500;
int n,m;
int dis[M],vis[M],cnt[M];
struct edge
{
	int to,cost;
}now;
vector<edge>v[M];
bool SPFA()
{
	queue<int>q;
	q.push(0);
	while (q.size())
	{
		int u=q.front();q.pop();vis[u]=0;
		for (int i=0;i<v[u].size();i++)
		{
			int go=v[u][i].to;
			int pay=v[u][i].cost;
			if (dis[go]<dis[u]+pay)
			{
				dis[go]=dis[u]+pay;
				cnt[go]++;
				if (cnt[go]>=n) {cout<<"-1";return 0;}
				if (!vis[go])
				{
					vis[go]=1;
					q.push(go);
				} 	
			}	
		}	
	}
	return 1;	
} 
int main()
{
	scanf("%d%d",&n,&m);
	for (int i=1;i<=m;i++)
	{
		int flag,a,b;
		scanf("%d%d%d",&flag,&a,&b);
		if (flag==1) now.to=b,now.cost=0,v[a].push_back(now);
		if (flag==1) now.to=a,now.cost=0,v[b].push_back(now);
		else if (flag==2) now.to=b,now.cost=1,v[a].push_back(now);
		else if (flag==3) now.to=a,now.cost=0,v[b].push_back(now);
		else if (flag==4) now.to=a,now.cost=1,v[b].push_back(now);
		else if (flag==5) now.to=b,now.cost=0,v[a].push_back(now);
		if ((flag==2||flag==4)&&(a==b)){cout<<"-1";return 0;}
	}
	for (int i=1;i<=n;i++)
	now.to=i,now.cost=1,v[0].push_back(now);
	if (SPFA())
	{
		long long int ans=0;
		for (int i=1;i<=n;i++) ans+=dis[i];
		cout<<ans;
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/acerandaker/article/details/80714774