码迷,mamicode.com
首页 > 其他好文 > 详细

bzoj2330: [SCOI2011]糖果 差分约束

时间:2016-07-30 19:39:02      阅读:138      评论:0      收藏:0      [点我收藏+]

标签:

这题有毒。首先显然是差分约束裸题,然而n,m<=1e5,并且有两个数据如下:

1、有负环的大数据。由于spfa判负环是o(nm)的,所以这个点要跑5s。然而这个点存在负的自环,可以直接判掉……

2、1->2->...->n的一条链。若1先入队,则可以一次更新完。否则每次编号较小的点会把所有编号大于它的点都重新更新一次,就卡到了o(n^2)。若一般的边表按1->n加边,入队顺序就是n->1。面向数据地,可以倒着加边,或者按1->n先把所有点入队。

有一个tarjan缩点,拓扑排序的做法,好像没有上述面向数据的问题。

#include<bits/stdc++.h>
#define N 100005
using namespace std;
int n,m,k,s,t;
struct edge{
	edge* s;
	int v,w;
}e[N*2],*back=e,*h[N];
void add(
int u,int v,int w){
	h[u]=&(*back++
	=(edge){h[u],v,w});
}
int d[N],a[N],z[N];
bool spfa(){
	queue<int> q;
	for(int i=1;i<=n;++i){
		q.push(i);
		d[i]=z[i]=1;
	}
	while(q.size()){
		int u=q.front();
		q.pop();
		z[u]=0;
		for(edge* i=h[u];i;i=i->s)
			if(d[i->v]<d[u]+i->w){
				if(++a[i->v]==n)
					return 0;
				d[i->v]=d[u]+i->w;
				if(!z[i->v]++)
					q.push(i->v);
			}
	}
	return 1;
}
int main(){
	scanf("%d%d",&n,&m);
	while(m--){
		scanf("%d%d%d",&k,&s,&t);
		if(k==1){
			add(s,t,0);
			add(t,s,0);
		}
		if(k==2)
			add(s,t,1);
		if(k==3)
			add(t,s,0);
		if(k==4)
			add(t,s,1);
		if(k==5)
			add(s,t,0);
	}
	printf("%lld\n",
	!spfa()?-1
	:accumulate(d+1,d+n+1,0ll));
}

  

bzoj2330: [SCOI2011]糖果 差分约束

标签:

原文地址:http://www.cnblogs.com/f321dd/p/5721443.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!