CF1215F Radio Stations
令 \(u\) 表示选择电站 \(u\) , \(u'\) 表示不选择电站 \(u\)。
首先可以简单的处理出电站之间的要求:
-
\(u,v\) 至少选一个,连边 \((u',v),(v',u)\)
-
\(u,v\) 至多选一个,连边 \((u,v'),(v,u')\)
可以枚举 \(f\) ,电站区间不包含 \(f\) 的强制不选 ( 连边\((u,u')\) ),然后用 \(\text{2-SAT}\) 求解。
考虑优化上述过程,\(f\) 对每个电站的要求可以看作两个:
- \(f\) 必须在 \([1,r_i]\) 之间
- \(f\) 必须不在 \([1,l_i)\) 之间
那么可以利用前缀优化建图,注意 \(f\) 不能为 \(0\) ,强制不选即可。
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
const int MAXN = 2e6 , MAXM = 2e6;
int n , k , m1 , m2 , l[ MAXN + 5 ] , r[ MAXN + 5 ];
int Enum , tmp[ MAXN + 5 ] , Head[ MAXN + 5 ];
struct Edge { int v , nxt; } Graph[ 2 * MAXM + 5 ];
void Add_Edge( int u , int v ) { Graph[ ++ Enum ] = { v , Head[ u ] }; Head[ u ] = Enum; }
int tim , cnt , dfn[ MAXN + 5 ] , low[ MAXN + 5 ] , bel[ MAXN + 5 ];
int Top , Stack[ MAXN + 5 ];
void Clear( ) {
tim = cnt = 0;
memset( dfn , 0 , sizeof( dfn ) );
memset( low , 0 , sizeof( low ) );
memset( bel , 0 , sizeof( bel ) );
}
void Tarjan( int u , int fa ) {
dfn[ u ] = low[ u ] = ++ tim;
Stack[ ++ Top ] = u;
for( int i = Head[ u ] ; i ; i = Graph[ i ].nxt ) {
int v = Graph[ i ].v; if( v == fa ) continue;
if( !dfn[ v ] ) {
Tarjan( v , u );
low[ u ] = min( low[ u ] , low[ v ] );
}
else if( !bel[ v ] )
low[ u ] = min( low[ u ] , dfn[ v ] );
}
if( dfn[ u ] == low[ u ] ) {
++ cnt;
for( ; Stack[ Top ] != u ; Top -- ) bel[ Stack[ Top ] ] = cnt;
bel[ Stack[ Top -- ] ] = cnt;
}
}
int main( ) {
scanf("%d %d %d %d",&m1,&n,&k,&m2);
for( int i = 1 , u , v ; i <= m1 ; i ++ ) {
scanf("%d %d",&u,&v);
Add_Edge( u + n , v ) , Add_Edge( v + n , u );
}
for( int i = 1 ; i <= n ; i ++ ) scanf("%d %d",&l[ i ],&r[ i ]);
for( int i = 1 , u , v ; i <= m2 ; i ++ ) {
scanf("%d %d",&u,&v);
Add_Edge( u , v + n ) , Add_Edge( v , u + n );
}
//2*n + 2*k
for( int i = 1 ; i <= k ; i ++ ) Add_Edge( 2 * n + i + 1 , 2 * n + i ); // > f
for( int i = k + 1 ; i >= 2 ; i -- ) Add_Edge( 2 * n + i - 1 + ( k + 1 ) , 2 * n + i + ( k + 1 ) ); // <= f
Add_Edge( 2 * n + 1 + ( k + 1 ) , 2 * n + 1 ); // f 不为 0
for( int i = 1 ; i <= n ; i ++ ) { //与 f 的限制
Add_Edge( i , 2 * n + r[ i ] + 1 + ( k + 1 ) ); Add_Edge( i , 2 * n + l[ i ] );
Add_Edge( 2 * n + r[ i ] + 1 , i + n ); Add_Edge( 2 * n + l[ i ] + ( k + 1 ) , i + n );
}
for( int i = 1 ; i <= 2 * n + 2 * ( k + 1 ) ; i ++ ) if( !dfn[ i ] ) Tarjan( i , 0 );
int num = 0 , f;
for( int i = 1 ; i <= n ; i ++ ) {
if( bel[ i ] == bel[ i + n ] ) { printf("-1\n"); return 0; }
if( bel[ i ] < bel[ i + n ] ) num ++;
}
for( int i = 1 ; i <= k ; i ++ ) if( ( bel[ 2 * n + i ] < bel[ 2 * n + i + ( k + 1 ) ] ) && ( bel[ 2 * n + i + 1 ] > bel[ 2 * n + i + 1 + ( k + 1 ) ] ) ) { f = i; break; }
printf("%d %d\n", num , f );
for( int i = 1 ; i <= n ; i ++ ) if( bel[ i ] < bel[ i + n ] ) printf("%d ", i );
return 0;
}