#回滚莫队,链表#洛谷 6349 [PA2011] Kangaroos

题目传送门


分析

首先区间 \([l,r]\)\([L,R]\) 相交当且仅当 \(l\leq R\)\(L\leq r\)(其实就是完全覆盖或者有一端点在区间中)

而且坐标范围太大了,如果要离散的话就更容易考虑离线了(在线也许比较难写?)

如果单单莫队的话左右端点的移动会非常麻烦,考虑回滚莫队,固定左端点所在块。

询问区间分为端点同块或者不同块两种情况,对于端点同块的情况,如果给定区间完全覆盖块那么可以直接计算进去

不能完全覆盖的话其中一个端点肯定在询问区间中,直接从询问区间的左端点枚举到右端点加入新的给定区间即可。

不同块的话左端点所在块的右端点是固定的,那么完全覆盖可以先考虑覆盖左端点所在块的右端点,

那么剩下可行区间仍然其中一个端点在询问区间中,块外向右扩展端点,块内回滚即可,维护最长连续段可以用链表


代码

#include <cstdio>
#include <cctype>
#include <vector>
#include <algorithm>
#include <cmath>
using namespace std;
const int N=200011,M=331;
struct rec{
    int l,r,rk;
    bool operator <(const rec &t)const{
        return r>t.r;
    }
}a[N],st[N*5/2];
int n,Q,pos[N],L[M],R[M],bl,Ans[N],ans,Top,ls[N],rs[N];
pair<int,int>b[N]; vector<rec>K[M];
int iut(){
    int ans=0,f=1; char c=getchar();
    while (!isdigit(c)) f=(c=='-')?-f:f,c=getchar();
    while (isdigit(c)) ans=ans*10+c-48,c=getchar();
    return ans*f;
}
void print(int ans){
    if (ans>9) print(ans/10);
    putchar(ans%10+48);
}
void Max(int &x,int y){x=x>y?x:y;}
void add(int x){
    if (ls[x]) return;
    st[++Top]=(rec){x,0,ans},ls[x]=rs[x]=x,Max(ans,1);
    if (ls[x-1]) st[++Top]=(rec){ls[x-1],rs[ls[x-1]],ans},st[++Top]=(rec){-rs[x],ls[rs[x]],ans},rs[ls[x-1]]=rs[x],ls[rs[x]]=ls[x-1],Max(ans,rs[ls[x]]-ls[rs[x]]+1);
    if (rs[x+1]) st[++Top]=(rec){-rs[x+1],ls[rs[x+1]],ans},st[++Top]=(rec){ls[x],rs[ls[x]],ans},ls[rs[x+1]]=ls[x],rs[ls[x]]=rs[x+1],Max(ans,rs[ls[x]]-ls[rs[x]]+1);
}
void BackTrace(int TOP){
    for (;Top>TOP;ans=st[Top--].rk)
    if (st[Top].l<0) ls[-st[Top].l]=st[Top].r;
        else if (st[Top].r) rs[st[Top].l]=st[Top].r;
            else ls[st[Top].l]=rs[st[Top].l]=0;
}
int main(){
    n=iut(),Q=iut(),bl=sqrt(2*n);
    for (int i=1;i<=n;++i){
        int l=iut(),r=iut();
        b[i*2-1]=make_pair(l,i);
        b[i*2]=make_pair(r,i);
    }
    sort(b+1,b+1+2*n);
    for (int i=1;i<=2*n;++i)
    if (a[b[i].second].l) a[b[i].second].r=i;
        else a[b[i].second].l=i;
    for (int i=1;i<=2*n;++i) pos[i]=(i-1)/bl+1;
    for (int i=1;i<=2*n;++i) if (!L[pos[i]]) L[pos[i]]=i;
    for (int i=2*n;i>=1;--i) if (!R[pos[i]]) R[pos[i]]=i;
    for (int i=1;i<=Q;++i){
        int l=iut(),r=iut();
        l=lower_bound(b+1,b+1+2*n,make_pair(l,0))-b;
        r=upper_bound(b+1,b+1+2*n,make_pair(r,n+1))-b-1;
        if (r<1||l>2*n) continue;
        K[pos[l]].push_back((rec){l,r,i});
    }
    for (int i=1;i<=pos[2*n];++i) if (!K[i].empty()){
        for (int j=1;j<=n;++j)
        if (a[j].l<L[i]&&R[i]<a[j].r) add(j);
        sort(K[i].begin(),K[i].end());
        int siz=K[i].size();
        for (;siz&&K[i][siz-1].r<=R[i];--siz){
            int TOP=Top;
            for (int j=L[i];j<=R[i];++j)
            if (a[b[j].second].l<=K[i][siz-1].r&&K[i][siz-1].l<=a[b[j].second].r)
                add(b[j].second);
            Ans[K[i][siz-1].rk]=ans,BackTrace(TOP);
        }
        BackTrace(0);
        if (siz){
            for (int j=1;j<=n;++j)
            if (a[j].l<=R[i]&&R[i]<=a[j].r) add(j);
            for (int now=R[i]+1;siz;--siz){
                for (;now<=K[i][siz-1].r;++now) add(b[now].second);
                int TOP=Top;
                for (int j=R[i];j>=K[i][siz-1].l;--j) add(b[j].second);
                Ans[K[i][siz-1].rk]=ans,BackTrace(TOP);
            }
            BackTrace(0);
        }
    }
    for (int i=1;i<=Q;++i) print(Ans[i]),putchar(10);
    return 0;
}
···
posted @ 2024-03-19 01:21  lemondinosaur  阅读(9)  评论(0编辑  收藏  举报