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;
}

浙公网安备 33010602011771号