【題解】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號