[BZOJ 2330]糖果
比较裸一些的差分约束系统题……话说好像第一次写SPFA最长路啊TAT
这个题1,3,5条件直接搞就可以。2,4条件要转化成有等于号的版本。
顺便说一些这题的坑点:
- 有一个点是一个十万个点的链。在从源点连的时候,如果正序连就会炸。倒着连就不会T。
- 有的点的2,4条件出现了[tex]a=b[/tex]的情况,要特判……
- 要开long long!
代码:
/**************************************************************
Problem: 2330
User: danihao123
Language: C++
Result: Accepted
Time:356 ms
Memory:7592 kb
****************************************************************/
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;
#define REP(i,n) for(i=1;i<=(n);i++)
#define GRAPH_REP(i,u) for(i=first[(u)];i;i=next[i])
#define CL_ARR(i,x) memset(i,x,sizeof(i))
const int maxn=100005,maxm=300005;
typedef long long ll;
int first[maxn];
int next[maxm],to[maxm];
ll dist[maxm];
int graph_cnt=0;
inline void AddEdge(int u,int v,ll d){
graph_cnt++;
next[graph_cnt]=first[u];
first[u]=graph_cnt;
to[graph_cnt]=v;
dist[graph_cnt]=d;
}
int n;
bool inQueue[maxn];
ll d[maxn];
int cnt[maxn];
ll SPFA(){
register int i,u;
register ll ans=0;
queue<int> Q;
CL_ARR(d,-1);
d[0]=0;
Q.push(0);
inQueue[0]=true;
while(!Q.empty()){
u=Q.front();
Q.pop();
inQueue[u]=false;
GRAPH_REP(i,u){
if(d[u]>-1 && d[to[i]]<d[u]+dist[i]){
d[to[i]]=d[u]+dist[i];
if(!inQueue[to[i]]){
Q.push(to[i]);
inQueue[to[i]]=true;
if((++cnt[to[i]])>(n+1))
return -1;
}
}
}
}
REP(i,n){
ans+=d[i];
}
return ans;
}
int main(){
register int i;
int opt,u,v;
int k;
scanf("%d%d",&n,&k);
REP(i,k){
scanf("%d%d%d",&opt,&u,&v);
if(opt==1){
AddEdge(u,v,0);
AddEdge(v,u,0);
}else{
if(opt==2){
if(u==v){
puts("-1");
return 0;
}
AddEdge(u,v,1);
}else{
if(opt==3){
AddEdge(v,u,0);
}else{
if(opt==4){
if(u==v){
puts("-1");
}
AddEdge(v,u,1);
}else{
AddEdge(u,v,0);
}
}
}
}
}
for(i=n;i>=1;i--){
AddEdge(0,i,1);
}
printf("%lld\n",SPFA());
return 0;
}