bzoj 2788 [Poi2012]Festival 差分约束+tarjan+floyd
题目大意
有n个正整数X1,X2,...,Xn,再给出m1+m2个限制条件,限制分为两类:
1.给出a,b (1<=a,b<=n),要求满足Xa + 1 = Xb
2.给出c,d (1<=c,d<=n),要求满足Xc <= Xd
在满足所有限制的条件下,求集合{Xi}大小的最大值。
分析
差分约束,问题很新颖
注意到图有特殊性
限制1(1类边):双向边
限制2(2类边):单向边
我们考虑求强联通分量
连接两个强联通分量的边不可能是1类边(不然强联通就合起来了)
只可能是A<=B
只要保证A中最大值小于B中最小值,就可以使不同权值最多
一定是可以做到的
那么我们只需要对每个强联通求出答案再累加起来就好了
对于强联通中的2类边,一定是在一个环中的,一定都为一个权值(不然就分成两个连通块了)
这一部分的最长路跑出来是0
由于图中只有-1,0,1三种边
每个强联通中,
记D为任意两个点的 最长路的绝对值 的最大值
其实D就是最大权值和最小权值的差
所以每个连通块权值种类就是D+1
姿势
1.差分约束常常特判连边是否自环矛盾
2.floyd判负环可以一开始f[i][i]=0,跑floyd的时候不判i!=j!=k,跑完后看看f[i][i]有没有变
3.邻接矩阵建图注意重编时取max,min啥的
4.之前我tarjan一直是写错的
if(inst[y]) low[x]=min(low[x],dfn[y]);//注意这里是inst[i],因为有向图搜索顺序的问题,tarjan是可能跑到之前tarjan过的地方的,如果写if(dfn[y])这样会出bug
else if(!dfn[y]){
tarjan(y);
low[x]=min(low[x],low[y]);
}
5.spfa时用que[],inq[]
6.spfa时inc函数既写引用又写返回值,方便一些
solution
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cctype>
#include <cmath>
#include <algorithm>
using namespace std;
const int M=607;
const int N=100007;
const int INF=2139062144;
inline int rd(){
int x=0;bool f=1;char c=getchar();
for(;!isdigit(c);c=getchar()) if(c=='-') f=0;
for(;isdigit(c);c=getchar()) x=x*10+c-48;
return f?x:-x;
}
int n,m1,m2;
int g[M],te;
struct edge{
int y,d,next;
}e[N<<1];
struct node{
int x,y;
node(int xx=0,int yy=0){x=xx;y=yy;}
}e1[N],e2[N];
void addedge(int x,int d,int y){
e[++te].y=y;e[te].d=d;e[te].next=g[x];g[x]=te;
}
int dfn[M],low[M],tdfn;
int col[M],cnt;
int st[M],tot;
int vis[M];
int f[M][M];
int ans[M];
int inst[M];
void tarjan(int x){
dfn[x]=low[x]=++tdfn;
st[++tot]=x;
inst[x]++;
int p,y;
for(p=g[x];p;p=e[p].next){
y=e[p].y;
if(inst[y]) low[x]=min(low[x],dfn[y]);//instack
else if(!dfn[y]){
tarjan(y);
low[x]=min(low[x],low[y]);
}
}
if(low[x]==dfn[x]){
++cnt;
while(st[tot]!=x){
inst[st[tot]]=0;
col[st[tot--]]=cnt;
}
inst[st[tot]]=0;
col[st[tot--]]=cnt;
}
}
void floyd(){
int i,j,k;
for(k=1;k<=n;k++)
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
if(f[i][k]!=-INF&&f[k][j]!=-INF){
f[i][j]=max(f[i][j],f[i][k]+f[k][j]);
}
}
int main(){
n=rd(),m1=rd(),m2=rd();
int i,j,x,y;
for(i=1;i<=m1;i++){
x=rd(),y=rd();
if(x==y){//²é·ÖÔ¼Êø³£¼ûÌØÅÐ
puts("NIE");
return 0;
}
e1[i]=node(x,y);
addedge(x,1,y);
addedge(y,-1,x);
}
for(i=1;i<=m2;i++){
x=rd(),y=rd();
e2[i]=node(x,y);
addedge(x,0,y);
}
for(i=1;i<=n;i++)
if(!dfn[i])
tarjan(i);
memset(f,128,sizeof(f));
for(i=1;i<=m1;i++){
x=e1[i].x,y=e1[i].y;
if(col[x]==col[y]){
f[x][y]=max(f[x][y],1);
f[y][x]=max(f[y][x],-1);
}
}
for(i=1;i<=m2;i++){
x=e2[i].x,y=e2[i].y;
if(col[x]==col[y]){
f[x][y]=max(f[x][y],0);
}
}
for(i=1;i<=n;i++) f[i][i]=0;//Åиº»·ÓÃ
floyd();
for(i=1;i<=n;i++) if(f[i][i]>0){
puts("NIE");
return 0;
}
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
if(col[i]==col[j]&&f[i][j]!=-INF) ans[col[i]]=max(ans[col[i]],abs(f[i][j]));///abs
int sum=0;
for(i=1;i<=cnt;i++) sum+=ans[i]+1;
printf("%d\n",sum);
return 0;
}