騷區間

題目鏈接:騷區間


顯然我們對每個左端點,可以ST表上二分,找到對應的合法右端點區間。

然後枚舉右端點,可以在ST表上二分,找到合法的左端點區間,我們把左端點區間排序一下,維護當前合法的左端點位置,然後fenwick上面查詢即可。


AC代碼:

#pragma GCC optimize("-Ofast","-funroll-all-loops")
#include<bits/stdc++.h>
//#define int long long
using namespace std;
const int N=1e6+10;
int fmi[N][25],fmx[N][25],a[N],n,d[N],cnt,lg[N]; long long res;
struct node{int id,l,r;}t[N];
struct heap{int id,r;};
bool operator < (heap a,heap b){return a.r>b.r;}
priority_queue<heap> q;
char *fs,*ft,buf[1<<20];
#define gc() (fs==ft&&(ft=(fs=buf)+fread(buf,1,1<<20,stdin),fs==ft))?0:*fs++;
inline int read(){
    int x=0,f=1; char ch=gc();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=gc();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=gc();}
    return x*f;
}
void ST(){
	int l=lg[n]+1;
	for(int j=1;j<l;j++)	for(int i=1;i<=n-(1<<j)+1;i++)
		fmx[i][j]=max(fmx[i][j-1],fmx[i+(1<<(j-1))][j-1]),
		fmi[i][j]=min(fmi[i][j-1],fmi[i+(1<<(j-1))][j-1]);
}
int askmx(int l,int r){int k=lg[r-l+1]; return max(fmx[l][k],fmx[r-(1<<k)+1][k]);}
int askmi(int l,int r){int k=lg[r-l+1]; return min(fmi[l][k],fmi[r-(1<<k)+1][k]);}
inline void insert(int x,int v){for(;x<=n;x+=x&(-x)) d[x]+=v;}
inline int ask(int x){int s=0; for(;x;x-=x&(-x)) s+=d[x]; return s;}
inline int ask(int l,int r){return ask(r)-ask(l-1);}
inline int find_r(int l,int r,int pos,int k){
	while(l<r){
		int mid=l+r>>1;
		if(askmi(pos+1,mid)<k)	r=mid;
		else	l=mid+1;
	}
	return l;
}
inline int find_l(int l,int r,int pos,int k){
	while(l<r){
		int mid=l+r+1>>1;
		if(askmx(mid,pos-1)>k)	l=mid;
		else	r=mid-1;
	}
	return l;
}
signed main(){
	n=read();	lg[0]=-1;
	for(int i=1;i<=1e6;i++)	lg[i]=lg[i>>1]+1;
	for(int i=1;i<=n;i++)	a[i]=read(),fmi[i][0]=fmx[i][0]=a[i]; ST();
	for(int i=1,l,r;i<n;i++)	if(askmi(i+1,n)<a[i]){
		l=find_r(i+1,n,i,a[i]);
		if(l==n||askmi(l+1,n)>=a[i])	r=n+1;
		else	r=find_r(l+1,n,l,a[i]);
		t[++cnt]={i,l,r-1};
	}
	sort(t+1,t+1+cnt,[](node a,node b){return a.l<b.l;}); int pos=1;
	for(int i=2;i<=n;i++){
		while(pos<=cnt&&t[pos].l<=i) insert(t[pos].id,1),q.push({t[pos].id,t[pos].r}),pos++;
		while(q.size()&&q.top().r<i) insert(q.top().id,-1),q.pop();
		if(askmx(1,i-1)>a[i]){
			int tr=find_l(1,i-1,i,a[i]),tl;
			if(tr==1||askmx(1,tr-1)<=a[i])	tl=0;
			else	tl=find_l(1,tr-1,tr,a[i]);
			res+=ask(tl+1,tr);
		}
	}
	cout<<res<<endl;
	return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章