Loading

【题解】Luogu P3740 [HAOI2014] 贴海报 / 离线区间推平

题意

给定一个长为 \(N\) 的区间,\(M\) 次区间推平操作。问区间上最后有多少个不同的值。

思路

离散化

区间可能有 \(10^7\) 这么长,但是只进行 \(1000\) 次推平操作。考虑对区间离散化,因为我们只关注区间端点的大小关系。但只离散化端点会造成一个问题:若一区间两端点都被其他区间推平,而中间部分没有,此时区间会在离散化后的序列中消失。造成此种情况的原因是,每个区间相当于延伸到了左右端点与相邻的下一个端点之间,进行推平操作时相当于会把不属于此区间的部分一并推平。解决方法是,离散化每个区间两端点外的一个点,相当于区间终止的标志符,两标志符之间的部分不会被一并推平,使推平操作正确。

离散化前:

pZxc9VP.png

离散化后:

pZxcCUf.png

注意到绿色部分原本属于红色区间,但离散化后没有这一段的点,相当于被黑蓝区间错误覆盖了,使红色区间错误地被隐藏。

区间推平

区间推平通常使用线段树。不过我们在离散化后,点数已经来到 \(10^3\) 量级,完全可以 \(O(n^2)\) 暴力。

不过此题只在所有操作完成后查询,更优的做法是离线。

后推平的区间会覆盖先推平的区间。考虑倒着做,这样区间推平就是先到先得了。每次只去修改还未推平过的区间。暴力做依然是 \(O(n^2)\)

优化方法是避免一个点被反复访问。用一个并查集维护已推平的区间的连通性,并维护每个区间的右端点(也可以直接合并到右端点上,用 \(fa_x\) 表示右端点)。每次推平一个点都去看他的相邻两点是否被推平过,如果推平过就与其所在的区间合并,并更新右端点。然后再推平的时候就可以直接跳过已推过的点了。路径压缩+按秩合并的时间复杂度为 \(O(n\alpha(n))\)

另一道类似的题是 Luogu P2391 白雪皑皑

实现

#include<bits/stdc++.h>
using namespace std;
const int N=4e3+10;
int n,m,idx,ans;
int l[N],r[N],d[N];
int fa[N],h[N];
int a[N],b[N];
bool vis[N],t[N];
int Find(int x){
    if(fa[x]==x) return x;
    else return fa[x]=Find(fa[x]);
}
void Merge(int x,int y){
    x=Find(x),y=Find(y);
    if(h[x]>h[y]) swap(x,y);
    fa[x]=y;
    if(h[x]==h[y]) h[y]++;
    b[y]=max(b[x],b[y]);
}
int main(){
    ios::sync_with_stdio(false);
    cin.tie(0),cout.tie(0);
    cin>>n>>m;
    for(int i=1;i<=m;i++){
        cin>>l[i]>>r[i];
        d[++idx]=l[i],d[++idx]=r[i];
        d[++idx]=l[i]-1,d[++idx]=r[i]+1;
    }
    sort(d+1,d+1+idx);
    idx=unique(d+1,d+1+idx)-d-1;
    for(int i=1;i<=m;i++){
        l[i]=lower_bound(d+1,d+1+idx,l[i])-d;
        r[i]=lower_bound(d+1,d+1+idx,r[i])-d;
    }
    for(int i=1;i<=idx;i++) fa[i]=b[i]=i,h[i]=1;
    for(int i=m;i>=1;i--){
        for(int j=l[i];j<=r[i];j++){
            if(!vis[j]){
                a[j]=i;
                vis[j]=1;
                if(vis[j-1]) Merge(j-1,j);
                if(vis[j+1]) Merge(j,j+1);
            }else j=b[Find(j)];
        }
    }
    for(int i=1;i<=idx;i++){
        if(!t[a[i]]&&a[i]) ans++,t[a[i]]=1;
    }
    cout<<ans;
    return 0;
}
posted @ 2026-02-26 11:58  Seqfrel  阅读(7)  评论(0)    收藏  举报