• 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;
    }
    
  • 相关阅读:
    和菜鸟一起学linux之bluetooth学习记录基础知识
    教父马云的经典语录汇总
    win32 多线程基础
    自己收集整理的微软错误代码大全(中文和英文)
    如何解决数据库中的字符型字段值中包含'0A'时,导出的文件用EXECEL打开时行数变多或者将结果导入数据库出错
    win32 TCP网络文件传输服务器端1.23
    Android窗口管理服务WindowManagerService对窗口的组织方式分析
    和菜鸟一起学linux总线驱动之DMA传输
    win 32下c语言文件传输客户端1.23
    Resolution to the record count increasing of the file exported from DB when ‘0A’ is included in it
  • 原文地址:https://www.cnblogs.com/Itst/p/12257993.html
Copyright © 2020-2023  润新知