CF538H Summer Dichotomy 二分图扫描线线段树
Posted itst
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了CF538H Summer Dichotomy 二分图扫描线线段树相关的知识,希望对你有一定的参考价值。
标算太NB
我觉得用这种做法,这道题难度只有2500
如果原图不是二分图显然无解。否则对于一个点数(geq 2)的连通块的两边可以缩成两个点,它们不能染相同的颜色。对于独立的点可以新建一个([0,10^9])的虚点让这个点和虚点不染相同颜色。然后就变成了有(n)个区间、(frac{n}{2})对限制,每个区间仅在一对限制中。
枚举颜色(1)中所有区间的交,这样对于每一对限制连接的两个区间就会有一些限制。
举个栗子:对于限制([l_1,r_1],[l_2,r_2]),假设(l_1<l_2<r_1<r_2),其余情况也是类似的推。假设当前枚举的交为(p):
如果(p<l_1)或(p>r_2)肯定没戏;
如果(l_1 leq p < l_2),那么区间([l_2,r_2])一定要染颜色(2);
如果(r_1 < p leq r_2),那么区间([l_1,r_1])一定要染颜色(2);
如果(l_2 leq p leq r_1),那么这两个区间都可以染颜色(1),因为有一个必须染颜色(2),可以认为是区间([l_1,r_2])一定要染颜色(2),然后根据最后选择了哪个位置选择究竟谁染颜色(2)。
那么可以得到(frac{n}{2})个必须要染颜色(2)的区间(如果某个限制没戏就是空区间)。对它们取交并检查是否存在位置与(p)的和(in [t,T])。如果存在就找到了一组解。取交操作可以使用动态开点线段树区间加区间(max)。
直接枚举效率太低,可以发现从小到大枚举(p)会使得某一个限制中必须要染颜色(2)的区间改变的改变点只有(O(n))种,所以离散化后扫描线即可。
#include<bits/stdc++.h>
using namespace std;
int read(){
int a = 0; char c = getchar(); while(!isdigit(c)) c = getchar();
while(isdigit(c)){a = a * 10 + c - 48; c = getchar();} return a;
}
const int _ = 1e5 + 7 , __ = _ * 40;
#define mid ((l + r) >> 1)
int ch[__][2] , mrk[__] , cnt; pair < int , int > mx[__];
void mark(int x , int v){mrk[x] += v; mx[x].first += v;}
void modify(int &x , int l , int r , int L , int R , int val){
if(!x){x = ++cnt; mx[x].second = l;}
if(l >= L && r <= R) return mark(x , val);
if(mid >= L) modify(ch[x][0] , l , mid , L , R , val);
if(mid < R) modify(ch[x][1] , mid + 1 , r , L , R , val);
mx[x] = max(mx[ch[x][0]] , mx[ch[x][1]]); mx[x].first += mrk[x];
}
pair < int , int > qry(int x , int l , int r , int L , int R){
if(l >= L && r <= R) return make_pair(mx[x].first , mx[x].second == 0 ? l : mx[x].second);
pair < int , int > mx(0 , 0); if(mid >= L) mx = qry(ch[x][0] , l , mid , L , R);
if(mid < R) mx = max(mx , qry(ch[x][1] , mid + 1 , r , L , R));
return make_pair(mx.first + mrk[x] , mx.second);
}
int t , T , N , M , col[_] , l[_] , r[_]; vector < int > nxt[_];
void dfs(int x , int c , vector < int > &L , vector < int > &R){
col[x] = c; (!c ? L : R).push_back(x);
for(auto t : nxt[x])
if(col[t] == c){puts("IMPOSSIBLE"); exit(0);}
else if(col[t] == -1) dfs(t , c ^ 1 , L , R);
}
struct mdy{int pos , l , r , val;}; vector < mdy > now;
void push(int p , int l , int r , int v){now.push_back((mdy){p , l , r , v});}
int main(){
t = read(); T = read(); N = read(); M = read(); memset(col , -1 , sizeof(col));
for(int i = 1 ; i <= N ; ++i){l[i] = read(); r[i] = read();}
for(int i = 1 ; i <= M ; ++i){int x = read() , y = read(); nxt[x].push_back(y); nxt[y].push_back(x);}
int num = 0;
for(int i = 1 ; i <= N ; ++i)
if(col[i] == -1){
int l1 = 0 , r1 = 1e9 , l2 = 0 , r2 = 1e9;
vector < int > L , R; dfs(i , 0 , L , R); ++num;
for(auto t : L){l1 = max(l1 , l[t]); r1 = min(r1 , r[t]);}
for(auto t : R){l2 = max(l2 , l[t]); r2 = min(r2 , r[t]);}
if(l1 > l2 || l1 == l2 && r1 < r2){swap(l1 , l2); swap(r1 , r2);}
if(l1 > r1 || l2 > r2){puts("IMPOSSIBLE"); return 0;}
if(r2 <= r1){
push(l1 , l2 , r2 , 1); push(l2 , l2 , r2 , -1); push(l2 , l1 , r1 , 1);
push(r2 + 1 , l1 , r1 , -1); push(r2 + 1 , l2 , r2 , 1); push(r1 + 1 , l2 , r2 , -1);
}
else if(l2 <= r1){
push(l1 , l2 , r2 , 1); push(l2 , l2 , r2 , -1); push(l2 , l1 , r2 , 1);
push(r1 + 1 , l1 , r2 , -1); push(r1 + 1 , l1 , r1 , 1); push(r2 + 1 , l1 , r1 , -1);
}
else{
push(l1 , l2 , r2 , 1); push(r1 + 1 , l2 , r2 , -1);
push(l2 , l1 , r1 , 1); push(r2 + 1 , l1 , r1 , -1);
}
}
sort(now.begin() , now.end() , [&](mdy x , mdy y){return x.pos < y.pos;});
int pos = 0 , rt = 0 , P1 = -1 , P2 = -1; now.push_back((mdy){T + 1 , 0 , 0 , 0});
while(pos < now.size() && now[pos].pos <= T){
int p1 = pos;
while(now[p1].pos == now[pos].pos){modify(rt , 0 , 1e9 , now[pos].l , now[pos].r , now[pos].val); ++pos;}
int L = max(0 , t - now[pos].pos + 1) , R = T - now[p1].pos;
pair < int , int > mx = qry(1 , 0 , 1e9 , L , R);
if(mx.first == num){P1 = mx.second; P2 = min(now[pos].pos - 1 , T - P1); break;}
}
if(P1 == -1) puts("IMPOSSIBLE");
else{
puts("POSSIBLE"); printf("%d %d
" , P1 , P2);
memset(col , -1 , sizeof(col));
for(int i = 1 ; i <= N ; ++i)
if(col[i] == -1){
int l1 = 0 , r1 = 1e9 , l2 = 0 , r2 = 1e9; vector < int > L , R; dfs(i , 0 , L , R);
for(auto t : L){l1 = max(l1 , l[t]); r1 = min(r1 , r[t]);}
for(auto t : R){l2 = max(l2 , l[t]); r2 = min(r2 , r[t]);}
if(!(l1 <= P1 && r1 >= P1 && l2 <= P2 && r2 >= P2)){
for(auto t : L) col[t] ^= 1;
for(auto t : R) col[t] ^= 1;
}
}
for(int i = 1 ; i <= N ; ++i) putchar(col[i] + '1');
}
return 0;
}
以上是关于CF538H Summer Dichotomy 二分图扫描线线段树的主要内容,如果未能解决你的问题,请参考以下文章
The bytes/str dichotomy in Python 3
Altium Designer Summer 09——元器件的封装
Summer training round2 #6 (Training #26)
Summer Programs之文科篇|Telluride Association Summer Program
Summer Programs之文科篇 | Telluride Association Summer Program介绍