CF526F Pudding Monsters
Pudding Monsters
题意
给定一个 \(1\) 到 \(n\) 的排列 \(p\),求其排序后连续的子区间个数。
\(1 \leq n \leq 3 \times 10^5\)。
思路
子区间 \([l,r]\) 排序后连续等价于 \(\max\limits_{i=l}^{r}p_i-\min\limits_{i=l}^{r}p_i=r-l\)。
考虑分治。假设当前处理到区间 \([L,R]\),我们只需要考虑跨越中线的子区间 \([l,r]\) 即可。发现满足条件的子区间 \([l,r]\) 可分为两大类。
如果最大值和最小值在同侧,不妨令其均在左侧。枚举所有满足 \(l \in [L,mid]\) 的左端点 \(l\),则有 \(r=\max\limits_{i=l}^{mid}p_i-\min\limits_{i=l}^{mid}p_i+l\),此时检查合法性即可,即:
-
\(r \in [mid+1,R]\)
-
\(\max\limits_{i=l}^{mid}p_i > \max\limits_{i=mid+1}^{r}p_i\)
-
\(\min\limits_{i=l}^{mid}p_i < \min\limits_{i=mid+1}^{r}p_i\)
如果最大值和最小值在异侧,不妨令最大值在左侧,最小值在右侧。考虑 \(\max\limits_{i=l}^{mid}p_i+l=\min\limits_{i=mid+1}^{r}p_i+r\)。如果我们已经固定 \(l\),此时要满足:
-
\(\max\limits_{i=l}^{mid}p_i > \max\limits_{i=mid+1}^{r}p_i\)
-
\(\min\limits_{i=l}^{mid}p_i > \min\limits_{i=mid+1}^{r}p_i\)
容易发现,依据这种大小关系,枚举 \(l\) 时 \(r\) 的候选区间是可以双指针的。
当最大值在右侧,最小值在左侧时,\(\min\limits_{i=l}^{mid}p_i-l=\max\limits_{i=mid+1}^{r}p_i-r\),要满足:
-
\(\max\limits_{i=l}^{mid}p_i < \max\limits_{i=mid+1}^{r}p_i\)
-
\(\min\limits_{i=l}^{mid}p_i < \min\limits_{i=mid+1}^{r}p_i\)
枚举 \(r\),此时 \(l\) 也可以双指针。
时间复杂度 \(O(n \log n)\)。
代码
#include<iostream>
#include<cstdio>
using namespace std;
long long ans;
int a[300010],maxn[300010],minn[300010],cnt[1000010];
void solve(int L,int R){
if(L==R){
ans++;
return ;
}
int lmid=(L+R)>>1,rmid=lmid+1,tmpl,tmpr;
solve(L,lmid);
solve(rmid,R);
maxn[lmid]=minn[lmid]=a[lmid];
for(int i=lmid-1;i>=L;i--){
maxn[i]=max(maxn[i+1],a[i]);
minn[i]=min(minn[i+1],a[i]);
}
maxn[rmid]=minn[rmid]=a[rmid];
for(int i=rmid+1;i<=R;i++){
maxn[i]=max(maxn[i-1],a[i]);
minn[i]=min(minn[i-1],a[i]);
}
for(int l=lmid;l>=L;l--){
int r=maxn[l]-minn[l]+l;
if(r>=rmid && r<=R && maxn[l]>maxn[r] && minn[l]<minn[r]){
ans++;
}
}
for(int r=rmid;r<=R;r++){
int l=minn[r]-maxn[r]+r;
if(l>=L && l<=lmid && maxn[l]<maxn[r] && minn[l]>minn[r]){
ans++;
}
}
tmpl=rmid,tmpr=rmid-1;
for(int l=lmid;l>=L;l--){
while(tmpr+1<=R && maxn[tmpr+1]<maxn[l]){
tmpr++;
cnt[minn[tmpr]+tmpr]++;
}
while(tmpl<=tmpr && minn[tmpl]>minn[l]){
cnt[minn[tmpl]+tmpl]--;
tmpl++;
}
ans+=cnt[maxn[l]+l];
}
while(tmpl<=tmpr){
cnt[minn[tmpl]+tmpl]--;
tmpl++;
}
tmpl=lmid+1,tmpr=lmid;
for(int r=rmid;r<=R;r++){
while(tmpl-1>=L && maxn[tmpl-1]<maxn[r]){
tmpl--;
cnt[minn[tmpl]-tmpl]++;
}
while(tmpr>=tmpl && minn[tmpr]>minn[r]){
cnt[minn[tmpr]-tmpr]--;
tmpr--;
}
ans+=cnt[maxn[r]-r];
}
while(tmpr>=tmpl){
cnt[minn[tmpr]-tmpr]--;
tmpr--;
}
}
int main(){
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++){
int x,y;
scanf("%d %d",&x,&y);
a[x]=y+n;
}
solve(1,n);
printf("%lld",ans);
return 0;
}

浙公网安备 33010602011771号