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 二分图扫描线线段树的主要内容,如果未能解决你的问题,请参考以下文章

CF 333E Summer Earnings

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介绍