CF1181E2 A Story of One Country (Hard) 题解

\(O(n \log n)\) 的做法。

\(O(n \log^ 2n)\) 的做法不过多赘述,我们还是先存下来所有矩形按照四种方式排序后的结果。

与原来做法不同的是,我们找到一个缝隙之后,不是立刻递归子问题,而是将要分裂出来的部分先打上一个颜色标记,然后从头开始重新扫描一遍,如果扫描过程中遇到有颜色的位置再用链表删除。当前子问题中,每个位置只会被删除一次。

重复扫描的过程,直到剩余部分 \(\le 3\)。此时再遍历当前所有的矩形,按照给他染上的颜色分类并递归子问题,因为是按照原顺序扫的所以无需排序。

上面整个部分是关于子问题大小线性的,类似原做法,递归子问题后,一定不存在一个子问题的大小 \(> \dfrac{n}{2}\),因此只会递归 \(O(\log n)\) 层,时间复杂度为 \(O(n\log n)\)

应该没问题吧。下面是写的有点烂的代码:

代码
#include<bits/stdc++.h>
const int N=1e5+5,INF=1e9;
int n;
struct NODE{int xl,xr,yl,yr;}p[N];
struct node{
    int l,r,id;
    node(int _l=0,int _r=0,int _id=0){l=_l,r=_r,id=_id;}
    bool friend operator<(node a,node b){
        if(a.l==b.l&&a.r==b.r)return a.id<b.id;
        return a.l==b.l?a.r<b.r:a.l<b.l;
    }
}a[4][N];
int nxt[4][N],id[4][N];
int col[N],inq[N];
std::vector<int> vec[N][4];
inline void Solve(){
    rd(n);
    std::queue<int> q;
    auto Tr=[&](int t,int id){
        if(t==0)return node(p[id].xl,p[id].xr,id);
        if(t==1)return node(-p[id].xr,-p[id].xl,id);
        if(t==2)return node(p[id].yl,p[id].yr,id);
        if(t==3)return node(-p[id].yr,-p[id].yl,id);
        return node();
    };
    for(int i=0;i<=n;i++)col[i]=inq[i]=0;
    for(int i=0;i<=n;i++)
        for(int t=0;t<4;t++)vec[i][t].clear();
    for(int i=1;i<=n;i++){
        rd(p[i].xl,p[i].yl,p[i].xr,p[i].yr);
        for(int t=0;t<4;t++)a[t][i]=Tr(t,i);
        for(int t=0;t<4;t++)id[t][i]=i;
    }
    for(int t=0;t<4;t++){
        id[t][n+1]=n+1;
        std::sort(id[t]+1,id[t]+n+1,[&](int x,int y){return a[t][x]<a[t][y];});
        for(int i=1;i<=n;i++)vec[0][t].push_back(id[t][i]);
    }

    q.push(0);
    int cnt=0;

    while(!q.empty()){
        int x=q.front();q.pop();
        int len=(int)vec[x][0].size();
        if(vec[x][0].size()<=3)continue;

        int now=0;
        for(int t=0;t<4;t++){
            for(int i=0;i<=len;i++)
                nxt[t][i]=i+1;
        }

        auto Next=[&](int t,int i){
            int j;
            for(j=nxt[t][i];j!=len+1;j=nxt[t][j]){
                if(col[vec[x][t][j-1]]==x)break;
            }
            nxt[t][i]=j;
            return j;
        };

        while(now+3<len){
            int flag=0;
            int it[4]={0,0,0,0},cur[4]={-INF,-INF,-INF,-INF};
            while(1){
                for(int t=0;t<4;t++)it[t]=Next(t,it[t]);
                if(Next(0,it[0])==len+1)break;
                for(int t=0;t<4;t++)cur[t]=std::max(cur[t],a[t][vec[x][t][it[t]-1]].r);
                for(int t=0;t<4;t++){
                    if(cur[t]<=a[t][vec[x][t][Next(t,it[t])-1]].l){
                        int nowp=0,ed=Next(t,it[t]);
                        ++cnt;
                        while(1){
                            nowp=Next(t,nowp);
                            if(nowp==ed)break;
                            col[vec[x][t][nowp-1]]=cnt;
                            ++now;
                        }
                        flag=1;
                        break;
                    }
                }
                if(flag)break;
            }
            if(!flag){
                puts("NO");
                return ;
            }
        }
        for(int t=0;t<4;t++){
            for(int i=0;i<len;i++){
                int k=vec[x][t][i];
                if(col[k]!=x){
                    vec[col[k]][t].push_back(k);
                    if(!inq[col[k]])inq[col[k]]=1,q.push(col[k]);
                }
            }
        }
    }
    puts("YES");
}
signed main(){
    Solve();
    return 0;
}
posted @ 2025-11-26 09:09  KIreteria  阅读(0)  评论(0)    收藏  举报