【题解】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();}
posted @ 2025-02-20 21:43  zhangxy__hp  阅读(10)  评论(0)    收藏  举报