【题解】CF 193D Two Segments
首先将枚举原排列中的区间转化为枚举值域上的区间。
从小往大对 \(r\) 扫描线,对于每个 \(l\in[1,r)\) 维护将 \([l,r]\) 在原排列中最少要分成多少段。显然只有 \(1\) 或 \(2\) 段才会产生贡献。那么我们用线段树维护值域上的每个 \(l\) 的最小段数,并维护值域区间上的最小值与最小值和最小值加一的数量。考虑加入 \(p_i\),如何影响我们维护的值。首先对于 \(l\in[1,p_i]\),要多出一段。如果 \(p_{i-1}<p_i\),那么对于 \(l\in[1,p_{i-1}]\),会减少一段。\(p_{i+1}\) 同理。直接在线段树上区间修改即可。时间复杂度 \(O(n\log n)\)。
#include<bits/stdc++.h>
#define ll long long
#define il inline
#define lid id<<1
#define rid id<<1|1
using namespace std;
namespace asbt{
namespace cplx{bool begin;}
const int maxn=3e5+5;
int n,a[maxn],b[maxn],tag[maxn<<2];
struct node{
int zhi,nm1,nm2;
node(int zhi=0,int nm1=0,int nm2=0):zhi(zhi),nm1(nm1),nm2(nm2){}
il node operator+(const node &x)const{
node res(min(zhi,x.zhi));
if(res.zhi==zhi){
res.nm1+=nm1;
res.nm2+=nm2;
}
else if(res.zhi+1==zhi){
res.nm2+=nm1;
}
if(res.zhi==x.zhi){
res.nm1+=x.nm1;
res.nm2+=x.nm2;
}
else if(res.zhi+1==x.zhi){
res.nm2+=x.nm1;
}
return res;
}
}tr[maxn<<2];
#define zhi(id) tr[id].zhi
#define nm1(id) tr[id].nm1
#define nm2(id) tr[id].nm2
il void pushup(int id){
tr[id]=tr[lid]+tr[rid];
}
il void pushtag(int id,int v){
tag[id]+=v,zhi(id)+=v;
}
il void pushdown(int id){
if(tag[id]){
pushtag(lid,tag[id]);
pushtag(rid,tag[id]);
tag[id]=0;
}
}
il void build(int id,int l,int r){
if(l==r){
nm1(id)=1;
return ;
}
int mid=(l+r)>>1;
build(lid,l,mid);
build(rid,mid+1,r);
pushup(id);
}
il void add(int id,int L,int R,int l,int r,int v){
if(l>r){
return ;
}
if(L>=l&&R<=r){
pushtag(id,v);
return ;
}
pushdown(id);
int mid=(L+R)>>1;
if(l<=mid){
add(lid,L,mid,l,r,v);
}
if(r>mid){
add(rid,mid+1,R,l,r,v);
}
pushup(id);
}
il int query(int id,int L,int R,int l,int r){
if(l>r){
return 0;
}
if(L>=l&&R<=r){
int res=0;
if(zhi(id)<=2){
res+=nm1(id);
}
if(zhi(id)<=1){
res+=nm2(id);
}
return res;
}
pushdown(id);
int mid=(L+R)>>1,res=0;
if(l<=mid){
res+=query(lid,L,mid,l,r);
}
if(r>mid){
res+=query(rid,mid+1,R,l,r);
}
return res;
}
#undef zhi
#undef nm1
#undef nm2
namespace cplx{
bool end;
il double usdmem(){return (&begin-&end)/1048576.0;}
}
int main(){
ios::sync_with_stdio(0),cin.tie(0);
cin>>n;
for(int i=1;i<=n;i++){
cin>>a[i];
b[a[i]]=i;
}
ll ans=0;
build(1,1,n);
for(int i=1;i<=n;i++){
add(1,1,n,1,i,1);
if(a[b[i]-1]<i){
add(1,1,n,1,a[b[i]-1],-1);
}
if(a[b[i]+1]<i){
add(1,1,n,1,a[b[i]+1],-1);
}
ans+=query(1,1,n,1,i-1);
}
cout<<ans;
return 0;
}
}
int main(){return asbt::main();}

浙公网安备 33010602011771号