CF538H Summer Dichotomy

cf

如果我们把题目里的边连出来以后出现了奇环就一定无解,否则我们对于每个连通块,先黑白染色,然后把同色的区间求交,合并成一个区间(如果是一个孤立点就加入 \([-\infty,+\infty]\) 作为这个和孤立点区间对立的区间),把得到的两个区间放在一个二元组里.现在相当于有若干个区间二元组 \(([l1,r1],[l2,r2])\),然后要决定二元组里每个区间的分别染成黑白,要使得存在两个数 \(n1,n2\),满足 \(t\le n1+n2\le 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\n",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\n",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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章