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;
}
posted @ 2021-04-08 20:22  chihik  阅读(34)  评论(0编辑  收藏  举报