[bzoj2788][Poi2012]Festival floyd 差分约束系统 tarjan

来源:互联网 发布:hibernate sql注入 编辑:程序博客网 时间:2024/06/05 10:56

2788: [Poi2012]Festival

Time Limit: 30 Sec  Memory Limit: 64 MB
[Submit][Status][Discuss]

Description


有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}大小的最大值。



Input


第一行三个正整数n, m1, m2 (2<=n<=600, 1<=m1+m2<=100,000)。

接下来m1行每行两个正整数a,b (1<=a,b<=n),表示第一类限制。

接下来m2行每行两个正整数c,d (1<=c,d<=n),表示第二类限制。



Output

一个正整数,表示集合{Xi}大小的最大值。


如果无解输出NIE。

Sample Input

4 2 2

1 2

3 4

1 4

3 1

Sample Output

3

HINT

|X3=1, X1=X4=2, X2=3


这样答案为3。容易发现没有更大的方案。



Source

差分约束建图先
首先跑一遍Floyd,如果一个点到自己的距离都小于0了,NIE!
然后tarjan缩点,可以想到各个环中各不影响(其实是贪到)
在一个环中如何统计最大点数?
我们可以知道,由于距离绝对值不大于1,假设在数轴上,一个环内所有点紧靠,那么可以取的个数就是环内最大距离+1
这道题我跑了16000+,有人跑了400+,都怪floyd太暴力了,由于我是懒癌所以。。就floyd吧
非常暴力的代码,邻接表还有个没用的v,懒得去了
#include<algorithm>#include<iostream>#include<cstring>#include<cstdio>using namespace std;const int N = 600 + 5;const int M = 2000000 + 5;struct Edge{int to,next;}e[M];int last[N*2],cnt;void insert( int u, int v, int w ){ e[++cnt].to = v; e[cnt].next = last[u]; last[u] = cnt; }int mp[N][N],dfn[N],low[N],scc,sta[N],cot,n,m1,m2,top,bel[N],ans; bool inq[N];void tarjan( int x ){low[x] = dfn[x] = ++cot;sta[++top] = x; inq[x] = 1;for( int i = last[x]; i; i = e[i].next )if( !dfn[e[i].to] ) tarjan(e[i].to),low[x]=min(low[x],low[e[i].to]);else if( inq[e[i].to] ) low[x] = min(low[x],dfn[e[i].to]);if( dfn[x] == low[x] ){int now = 0; scc++;while( now != x ){now = sta[top--];bel[now] = scc;inq[now] = 0;}}}int main(){scanf("%d%d%d", &n, &m1, &m2);memset(mp,0x3f,sizeof(mp));for( int i = 1,u,v; i <= m1; i++ ){scanf("%d%d", &u, &v);mp[u][v] = min(mp[u][v],1); mp[v][u] = min(mp[v][u],-1);insert( u, v, 1 ); insert( v, u, -1 );}for( int i = 1,u,v; i <= m2; i++ ){scanf("%d%d", &u, &v);mp[v][u] = min(mp[v][u],0);insert( v, u, 0 );}for( int i = 1; i <= n; i++ ) mp[i][i] = 0;for( int k = 1; k <= n; k++ )for( int i = 1; i <= n; i++ )for( int j = 1; j <= n; j++ )mp[i][j] = min( mp[i][j], mp[i][k]+mp[k][j] );for( int i = 1; i <= n; i++ ) if( mp[i][i] < 0 ){ puts("NIE"); return 0; }for( int i = 1; i <= n; i++ ) if( !dfn[i] ) tarjan(i);for( int i = 1; i <= scc; i++ ){int now = 0;for( int j = 1; j <= n; j++ )if( bel[j] == i )for( int k = 1; k <= n; k++ )if( bel[k] == i ) now = max(now,mp[j][k]);ans += now+1;}printf("%d\n", ans);return 0;}