CF2111G Divisible Subarrays

题目传送门

思路

这个交互其实就是个强制在线,没有其他用处。

为了方便,对于一个横坐标 \(x_1\sim x_2\),纵坐标 \(y_1\sim y_2\) 的矩阵。我们用 \((x_1,x_2,y_1,y_2)\) 来描述。

首先考虑对于每一个 \(l\),二分一个最远的 \(r\) 使得 \([l,r]\) 合法。

然后你仔细想一下,发现如果一个区间 \([l,r]\) 合法,它的分界点在 \(r\) 的话,\([l,r-1]\) 未必合法。所以这个二分是假的。

转化一下题意:把原排列按是否 \(\le x\) 搞成 \(01\) 序列,那么合法的序列就是一段 \(0\) 拼上一段 \(1\)

这个东西直接套路的扫描线扫值域就行,发现每次会有一个 \(0\) 变为 \(1\)

注意到每次合法的区间相当于,从序列里选出来恰好由一段 \(0\) 一段 \(1\) 构成,且左右端点两边的数都与端点不相同的子段。然后就是在左边那段选一个位置,右边那段选一个位置,比方说选了 \(l,r\),那么区间 \([l,r]\) 就是合法的。

注意到对于每两个相邻的连续段,合法的区间形如一个矩阵(左端点(横坐标)在 \([l,x]\),右端点(纵坐标)在 \([x+1,r]\))。

然后我们就需要,支持 \(q\) 次询问一个点是否被某个矩形覆盖过。

不难发现每次 \(01\) 序列变化后,变化的矩阵数量为 \(O(1)\) 级别的,所以可以暴力搞出来所有矩阵,然后直接上主席树维护。

但是这个东西会有一些冗余。注意到我们只需要考虑之前没有出现的矩形。

比方说现在有三个 \(01\) 连续段,中间的连续段有一个 \(0\) 要变成 \(1\)。首先新增的是改的那个位置到原来它所在段的每个位置(除了自己)。

然后如果这个位置 \(i\) 旁边有至少一个 \(1\),还会增加形如 \((x,y,i,i)\)\((i,i,x,y)\) 的矩阵。

于是我们把所有矩形搞了出来,把这个矩形的贡献拆到 \(x_1\)\(x_2+1\) 上丢进主席树里维护就好了。由于每次更改是区间加,所以要标记永久化。

代码

#include<bits/stdc++.h>
// #define int long long
#define N 800005
#define inf 2e18
#define mod 1000000007
#define pii pair<int,int>
#define x first
#define y second
using namespace std;
int T=1,n,q,a[N],p[N],rt[N],bel[N];
struct node{
    int l1,r1,l2,r2;
};
struct seg{
    int l,r,v;
};
vector<node>all;
vector<seg>qry[N];
struct dsgt{
    int ls[N<<5],rs[N<<5],tr[N<<5],lzy[N<<5],cnt;
    int build(int l,int r){
        int p=++cnt;
        if(l==r)return p;
        int mid=l+r>>1;
        ls[p]=build(l,mid);
        rs[p]=build(mid+1,r);
        return p;
    }
    void modify(int &p,int pre,int l,int r,int L,int R,int v){
        p=++cnt;
        tr[p]=tr[pre]+(min(r,R)-max(l,L)+1)*v;
        lzy[p]=lzy[pre];
        ls[p]=ls[pre];
        rs[p]=rs[pre];
        if(l>=L&&r<=R){
            lzy[p]+=v;
            return;
        }
        int mid=l+r>>1;
        if(L<=mid)modify(ls[p],ls[pre],l,mid,L,R,v);
        if(R>mid)modify(rs[p],rs[pre],mid+1,r,L,R,v);
    }
    int qry(int p,int l,int r,int L,int R,int sum){
        if(l>=L&&r<=R)return tr[p]+sum*(r-l+1);
        int mid=l+r>>1;
        int res=0;
        if(L<=mid)res+=qry(ls[p],l,mid,L,R,sum+lzy[p]);
        if(R>mid)res+=qry(rs[p],mid+1,r,L,R,sum+lzy[p]);
        return res;
    }
}dsgt;
void solve(int cs){
    if(!cs)return;
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        scanf("%d",&a[i]);
        p[a[i]]=i;
    }
    set<int>s0,s1;
    s0.insert(0);
    s0.insert(n+1);
    s1.insert(0);
    s1.insert(n+1);
    for(int i=1;i<=n;i++){
        s0.insert(i);
    }
    for(int j=1;j<=n;j++){
        int i=p[j];
        auto ao=s1.lower_bound(i);
        int nxt=(*ao)-1;
        ao--;
        int pre=(*ao)+1;
        if(a[i-1]>a[i])all.push_back({pre,i-1,i,i});
        if(a[i+1]>a[i])all.push_back({i,i,i+1,nxt});
        s0.erase(i);
        s1.insert(i);
        if(a[i-1]>a[i]&&a[i+1]>a[i])continue;
        if(a[i-1]<a[i]&&a[i+1]<a[i]){
            auto it1=s0.upper_bound(i);
            int r=(*it1)-1;
            it1--;
            int l=(*it1)+1;
            auto it=s1.lower_bound(l);it--;
            int L=(*it)+1;
            it=s1.upper_bound(r);
            int R=(*it)-1;
            all.push_back({L,l-1,l,r});
            all.push_back({l,r,r+1,R});
        }
        else{
            if(a[i-1]<a[i]){
                auto it1=s0.lower_bound(i);it1--;
                int r=(*it1);
                if(r>0){
                    auto it=s1.lower_bound(r);it--;
                    int l=(*it)+1;
                    all.push_back({l,r,i,i});
                }
            }
            else{
                auto it1=s0.upper_bound(i);
                int l=(*it1);
                if(l<n+1){
                    auto it=s1.upper_bound(l);
                    int r=(*it)-1;
                    all.push_back({i,i,l,r});
                }
            }
        }
    }
    for(auto it:all){
        if(it.l1>it.r1||it.l2>it.r2)continue;
        qry[it.l1].push_back({it.l2,it.r2,1});
        qry[it.r1+1].push_back({it.l2,it.r2,-1});
    }
    rt[0]=dsgt.build(1,n);
    for(int i=1;i<=n;i++){
        dsgt.modify(rt[i],rt[i-1],1,n,1,n,0);
        for(auto it:qry[i]){
            dsgt.modify(rt[i],rt[i],1,n,it.l,it.r,it.v);
        }
    }
    scanf("%d",&q);
    for(int i=1;i<=q;i++){
        int l,r;
        scanf("%d%d",&l,&r);;
        if(dsgt.qry(rt[l],1,n,r,r,0))printf("YES\n");
        else printf("NO\n");
        if(i%10==0)fflush(stdout);
    }
}
signed main(){
    ios::sync_with_stdio(0);
    cin.tie(0);cout.tie(0);
    // init();
    // cin>>T;
    for(int cs=1;cs<=T;cs++){
        solve(cs);
    }
    return 0;
}
posted @ 2025-06-07 12:30  zxh923  阅读(11)  评论(0)    收藏  举报