[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; }