BZOJ 2330 [SCOI2011]糖果
差分约束的裸题,虽然我不会。
第一次见差分约束还是之前考试看LLJ大佬写的,感觉十分神奇。
a==b||a>=b||a<=b时连0的边;
a>b,a<b时连1的边;
因为每个小朋友都要吃糖,增设源点向每个小朋友连1的边;
然后跑最长路;
注意,等于的时候要连双向边,spfa时要判负环。
然后十分神奇的是据说这题要卡spfa,加源点的时候连边要从n到1,不然会被卡。
我:LLJ大佬,什么时候别人要卡我的spfa怎么办呀?
LLJ大佬:你可以rand一下,给每条边设个优先值,按优先值加啊。
我:太强啦!
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<queue>
#include<vector>
typedef long long LL;
const int maxn=200000+299;
int fl,n,k,x,a,b,ecnt,fir[maxn],nxt[maxn*2],to[maxn*2],val[maxn*2],vis[maxn],in[maxn];
LL dis[maxn],ans;
using namespace std;
int read() {
int aa=0;char cc=getchar();
while(cc<'0'||cc>'9') cc=getchar();
while(cc>='0'&&cc<='9') aa=aa*10+cc-'0',cc=getchar();
return aa;
}
void add(int u,int v,int w) {
nxt[++ecnt]=fir[u]; fir[u]=ecnt; to[ecnt]=v; val[ecnt]=-w;
}
void init() {
n=read(); k=read();
for(int i=n;i>=1;i--) add(n+1,i,1);
for(int i=1;i<=k;i++) {
//scanf("%d%d%d",&x,&a,&b);
x=read(); a=read(); b=read();
if(a==b&&x!=1&&x!=3&&x!=5) fl=1;
else {
if(x==1) add(b,a,0),add(a,b,0);
if(x==2) add(a,b,1);
if(x==3) add(b,a,0);
if(x==4) add(b,a,1);
if(x==5) add(a,b,0);
}
}
}
queue<int>que;
void spfa() {
memset(dis,127,sizeof(dis));
memset(vis,0,sizeof(vis));
que.push(n+1);
vis[n+1]=1; dis[n+1]=0;
while(!que.empty()) {
int x=que.front();
que.pop(); vis[x]=0;
for(int i=fir[x];i;i=nxt[i]) {
if(dis[to[i]]>dis[x]+val[i]) {
dis[to[i]]=dis[x]+val[i];
if(!vis[to[i]]) {
vis[to[i]]=1;
in[to[i]]++;
if(in[to[i]]>n) { ans=-1; return;}
que.push(to[i]);
}
}
}
}
for(int i=1;i<=n;i++) ans-=dis[i];
}
void work() {
if(fl) ans=-1;
else spfa();
printf("%lld\n",ans);
}
int main()
{
//freopen(".in","r",stdin);
//freopen(".out","w",stdout);
init();
work();
return 0;
}