CF538H Summer Dichotomy

cf

如果我们把题目里的边连出来以后出现了奇环就一定无解,否则我们对于每个连通块,先黑白染色,然后把同色的区间求交,合并成一个区间(如果是一个孤立点就加入 ([-infty,+infty]) 作为这个和孤立点区间对立的区间),把得到的两个区间放在一个二元组里.现在相当于有若干个区间二元组 (([l1,r1],[l2,r2])),然后要决定二元组里每个区间的分别染成黑白,要使得存在两个数 (n1,n2),满足 (tle n1+n2le T),且 (n1) 被所有黑区间包含, (n2) 被所有白区间包含

上述限制条件可以改为:黑白染色后得到黑区间的交为 ([pl,pr]),白区间的交为 ([ql,qr]),要满足 ([pl+ql,pr+qr])([t,T]) 区间有交.可以发现所有二元组里的区间最大左端点 (zl) 一定为 (pl)(ql) 中的一个,区间最小右端点 (zr) 一定为 (pr)(qr) 中的一个,那么我们找到最大左端点和最小右端点所在二元组,并枚举最大左端点和最小右端点对应的区间是否同色,那么这时可以先把这两个(或一个)二元组的染色情况确定下来,然后去确定其他二元组的染色.后面默认最大左端点对应区间是黑色的

由于我们先确定了全局的最大左端点和最小右端点,那如果把最大左端点对应的交区间和后面的区间求交,那么只有交区间的右端点会变小,同理最小右端点对应的颜色的交区间只有左端点会变大.现在就从小到大枚举白色对应交区间的左端点 (l_0),这时左端点比当前枚举值更小的二元组里的区间都可以被染成白色.再考虑另一个没确定的右端点(即和最小右端点对应区间不同色的交区间的右端点) (r_0) ,因为这时相当于 (pl+ql) 已确定,那么显然这个 (r_0) 是越大越好.对于其他二元组,如果有一个区间可以染白,那么另一个区间的右端点就要去限制 (r_0) 大小,如果两个两个区间都可以被染白,那么选择右端点更大的区间去限制那个 (r_0) 更优.所以这里可以用 (mathrm{multiset}) 来维护其他二元组的用来限制 (r_0) 的右端点,然后取最小值作为 (r_0).如果所有其他二元组都存在可以染白的区间,那就可以用当前的 (l_0,r_0) 和最大左端点 (zl) ,最小右端点 (zr) 作为 ([pl,pr],[ql,qr]),这时满足限制条件就可以输出答案

注意 (l_0) 要和 还没染色时的黑色交区间左端点 取 max,(r_0) 同理,以及要构造合法的 (n_1,n_2)

#include<bits/stdc++.h>
#define LL long long

using namespace std;
const int N=2e5+10;
int rd()
{
    int x=0,w=1;char ch=0;
    while(ch<'0'||ch>'9'){if(ch=='-') w=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+(ch^48);ch=getchar();}
    return x*w;
}
int to[N<<1],nt[N<<1],hd[N],tot=1;
void adde(int x,int y)
{
    ++tot,to[tot]=y,nt[tot]=hd[x],hd[x]=tot;
    ++tot,to[tot]=x,nt[tot]=hd[y],hd[y]=tot;
}
int sl,sr,n,m,ra[N][2],a[N][2],tt=1,ff[N],co[N],sq[N],tp,cn[N];
bool an[N];
queue<int> q;
bool cmp(int aa,int bb){return a[aa][0]<a[bb][0];}
multiset<int> sb;

int main()
{
    sl=rd(),sr=rd(),n=rd(),m=rd();
    for(int i=1;i<=n;++i) ra[i][0]=rd(),ra[i][1]=rd();
    a[0][0]=-1,a[0][1]=2e9;
    for(int i=1;i<=m;++i) adde(rd(),rd());
    for(int i=1;i<=n;++i)
	if(!ff[i])
	{
	    ++tt,a[tt][0]=a[0][0],a[tt][1]=a[0][1];
	    ++tt,a[tt][0]=a[0][0],a[tt][1]=a[0][1];
	    ff[i]=tt-1,q.push(i);
	    while(!q.empty())
	    {
    		int x=q.front();
    		q.pop();
    		int xt=tt^1^co[x];
    		a[xt][0]=max(a[xt][0],ra[x][0]),a[xt][1]=min(a[xt][1],ra[x][1]);
    		for(int j=hd[x];j;j=nt[j])
    		{
    		    int y=to[j];
    		    if(ff[y])
    		    {
    		    	if(co[x]==co[y]){puts("IMPOSSIBLE");return 0;}
    		    }
    		    else ff[y]=ff[x]^1,co[y]=co[x]^1,q.push(y);
    		}
	    }
	    if(a[tt-1][0]>a[tt-1][1]||a[tt][0]>a[tt][1]){puts("IMPOSSIBLE");return 0;}
	}
    int m1=0,m2=0;
    for(int i=2;i<=tt;++i)
    {
    	if(a[i][0]>a[m1][0]) m1=i;
	    if(a[i][1]<a[m2][1]) m2=i;
    }
    if(a[m1][0]<=a[m2][1])
    {
    	int z1=a[m1][0],z2=a[m2][1],pl=max(max(a[m1^1][0],a[m2^1][0]),0),pr=min(a[m1^1][1],a[m2^1][1]),rs=(tt>>1)-2+((m1>>1)==(m2>>1));
    	an[m1>>1]=m1&1,an[m2>>1]=m2&1;
    	for(int i=2;i<=tt;++i)
    	    if((i>>1)!=(m1>>1)&&(i>>1)!=(m2>>1)) sq[++tp]=i;
    	sort(sq+1,sq+tp+1,cmp);
    	sb.insert(pr);
    	for(int i=0;i<=tp;++i)
    	{
    	    int x=sq[i];
    	    if(x)
    	    {
        		if(a[x][0]>pr) break;
        		++cn[x>>1];
        		if(cn[x>>1]==1) --rs,sb.insert(a[x][1]),an[x>>1]=(x&1)^1;
        		else
        		{
        		    int y=x^1;
        		    if(a[x][1]>a[y][1])
        			sb.erase(sb.find(a[y][1])),sb.insert(a[x][1]),an[x>>1]^=1;
        		}
    	    }
    	    int nl=max(pl,a[x][0]),nr=(*sb.begin());
    	    if(rs<=0&&nl<=nr&&max(nl+z1,sl)<=min(nr+z2,sr))
    	    {
        		puts("POSSIBLE");
        		int mm=sl-(z1+nl);
        		if(mm>0)
        		{
        		    if(z1+mm<=z2) z1+=mm;
        		    else nl+=mm-(z2-z1),z1=z2;
        		}
        		printf("%d %d
",z1,nl);
        		for(int i=1;i<=n;++i) printf("%d",1+((an[ff[i]>>1]^ff[i])&1));
        		return 0;
    	    }
    	}
    }
    tp=0;
    sb.clear();
    memset(cn,0,sizeof(cn));
    if(m1!=m2)
    {
    	int z1=a[m1][0],z2=a[m2][1],pl=max(max(a[m1^1][0],a[m2][0]),0),pr=min(a[m1][1],a[m2^1][1]),rs=(tt>>1)-2+((m1>>1)==(m2>>1));
    	an[m1>>1]=m1&1,an[m2>>1]=(m2&1)^1;
    	for(int i=2;i<=tt;++i)
    	    if((i>>1)!=(m1>>1)&&(i>>1)!=(m2>>1)) sq[++tp]=i;
    	sort(sq+1,sq+tp+1,cmp);
    	sb.insert(pr);
    	for(int i=0;i<=tp;++i)
    	{
    	    int x=sq[i];
    	    if(x)
    	    {
        		if(a[x][0]>z2) break;
        		++cn[x>>1];
        		if(cn[x>>1]==1) --rs,sb.insert(a[x^1][1]),an[x>>1]=(x&1)^1;
        		else
        		{
        		    int y=x^1;
        		    if(a[y][1]>a[x][1])
        			sb.erase(sb.find(a[x][1])),sb.insert(a[y][1]),an[x>>1]^=1;
        		}
    	    }
    	    int nl=max(pl,a[x][0]),nr=(*sb.begin());
    	    if(rs<=0&&z1<=nr&&nl<=z2&&max(nl+z1,sl)<=min(nr+z2,sr))
    	    {
        		puts("POSSIBLE");
        		int mm=sl-(z1+nl);
        		if(mm>0)
        		{
        		    if(z1+mm<=nr) z1+=mm;
        		    else nl+=mm-(nr-z1),z1=nr;
        		}
        		printf("%d %d
",z1,nl);
        		for(int i=1;i<=n;++i) printf("%d",1+((an[ff[i]>>1]^ff[i])&1));
        		return 0;
    	    }
    	}
    }
    puts("IMPOSSIBLE");
    return 0;
}
原文地址:https://www.cnblogs.com/smyjr/p/12337253.html