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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章