權值線段樹+思維 牛客練習賽66 E題 騷區間

騷區間

這種貢獻題可以發現,固定一個右邊界 i ,然後在 1–i-1 找出所有符合條件的左邊界 j ;

所以可以預處理出在 (1–i-1) 中大於 a[i] 的第一個元素位置p1,和第二個元素位置p2, 那麼(p2+1,p1)就是可以成爲 i 的左邊界,同樣可以處理右邊界;這裏可以運用權值線段樹,查找最大最小座標;

最後可以運用差分原理,統計答案;

代碼:

#include<bits/stdc++.h>
#define LL long long
#define pa pair<int,int>
#define ls k<<1
#define rs k<<1|1
#define inf 0x3f3f3f3f
using namespace std;
const int N=1000100;
const int M=2000100;
const LL mod=1e9+7;
int a[N],n,l1[N],r1[N],l2[N],r2[N]; 
vector<pa>ve[N];
struct Node{
	int l,r,mx,mi;
	LL w;
}tr[N*4];
void pp(int k){
	tr[k].mx=max(tr[ls].mx,tr[rs].mx);
	tr[k].mi=min(tr[ls].mi,tr[rs].mi);
	tr[k].w=tr[ls].w+tr[rs].w;
} 
void build(int l,int r,int k){
	tr[k].l=l,tr[k].r=r;
	if(l==r){
		tr[k].mx=0,tr[k].mi=2e9,tr[k].w=0;
		return;
	}
	int d=(l+r)>>1;
	build(l,d,ls);
	build(d+1,r,rs);
	pp(k);
}
void update_pos1(int pos,int w,int k){
	if(tr[k].l==tr[k].r){
		tr[k].mx=w;
		return;
	}
	int d=(tr[k].l+tr[k].r)>>1;
	if(pos<=d) update_pos1(pos,w,ls);
	else update_pos1(pos,w,rs);
	pp(k);
}
int query_pos1(int l,int r,int k){
	if(l>r) return 0;
	if(tr[k].l>=l&&tr[k].r<=r) return tr[k].mx;
	int d=(tr[k].l+tr[k].r)>>1;
	if(r<=d) return query_pos1(l,r,ls);
	if(l>d) return query_pos1(l,r,rs);
	return max(query_pos1(l,r,ls),query_pos1(l,r,rs));
}
void update_pos2(int pos,int w,int k){
	if(tr[k].l==tr[k].r){
		tr[k].mi=w;
		return;
	}
	int d=(tr[k].l+tr[k].r)>>1;
	if(pos<=d) update_pos2(pos,w,ls);
	else update_pos2(pos,w,rs);
	pp(k);
}
int query_pos2(int l,int r,int k){
	if(l>r) return 2e9;
	if(tr[k].l>=l&&tr[k].r<=r) return tr[k].mi;
	int d=(tr[k].l+tr[k].r)>>1;
	int ans=2e9;
	if(r<=d) return query_pos2(l,r,ls);
	if(l>d) return query_pos2(l,r,rs);
	return min(query_pos2(l,r,ls),query_pos2(l,r,rs));
}
void update(int pos,int w,int k){
	if(tr[k].l==tr[k].r){
		tr[k].w+=(LL)w;
		return;
	}
	int d=(tr[k].l+tr[k].r)>>1;
	if(pos<=d) update(pos,w,ls);
	else update(pos,w,rs);
	pp(k);
}
LL query(int l,int r,int k){
	if(l>r) return 0;
	if(tr[k].l>=l&&tr[k].r<=r) return tr[k].w;
	LL ans=0;
	int d=(tr[k].l+tr[k].r)>>1;
	if(l<=d) ans+=query(l,r,ls);
	if(r>d) ans+=query(l,r,rs);
	return ans;
}
int main(){
	scanf("%d",&n);
	for(int i=1;i<=n;i++) scanf("%d",&a[i]);
	build(1,n,1);
	for(int i=1;i<=n;i++){
		int pos1=query_pos1(a[i]+1,n,1);//查找大於a[i]的元素最大下標 
		if(pos1){
			r1[i]=pos1;
			l1[i]=query_pos1(a[i]+1,a[pos1]-1,1)+1;
			l1[i]=max(l1[i],query_pos1(a[pos1]+1,n,1)+1);
		}
		update_pos1(a[i],i,1);
	}
	build(1,n,1);
	for(int i=n;i>=1;i--){
		int pos2=query_pos2(1,a[i]-1,1);//查找小於a[i]的元素最小下標 
		if(pos2!=2e9){
			l2[i]=pos2;
			r2[i]=query_pos2(1,a[pos2]-1,1)-1;
			r2[i]=min(r2[i],query_pos2(a[pos2]+1,a[i]-1,1)-1);
			if(r2[i]>n) r2[i]=n;
		}
		update_pos2(a[i],i,1);
	}
	for(int i=1;i<=n;i++){
		if(l2[i]&&r2[i]){
			ve[l2[i]].push_back(pa(i,1));
			ve[r2[i]+1].push_back(pa(i,-1));
		}
	}
	LL ans=0;
	for(int i=1;i<=n;i++){
		for(int j=0;j<ve[i].size();j++) update(ve[i][j].first,ve[i][j].second,1);
		if(l1[i]&&r1[i]) ans+=query(l1[i],r1[i],1);
	}
	printf("%lld\n",ans);
	return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章