XSY原创题 序列

题目大意

给定长为$n$的序列$A$,定义长为$k$的区间中位数为从小到大排完序后第$\lfoor\frac{k}{2}\rfloor$的子区间大小。

每次询问给定$l_1,r_1,l_2,r_2$有多少个子区间满足中位数$\in[l_1,r_1]$长度$\in[l_2,r_2]$。

询问不超过五组。

题解

将问题提转化成中位数$\leq K$,长度$\in [l,r]$的子区件有多少个,答案相减即为最终答案。

发现对于每一个$A_i$,若子区间内$A_i\leq K$的数量至少达到区间长度的一半即可。

那么将$A_i\leq K$看做$1$,否则看做$-1$,求区间和$\geq 0$,区间长度$\in [l,r]$的数量即可。

这个只需要用主席树或者删电加点的树状数组维护即可。

复杂度$O(2nm\log n)$。

#include<bits/stdc++.h>
#define debug(x) cerr<<#x<<" = "<<x
#define sp <<"  "
#define el <<endl
#define LL long long
#define M 100020
using namespace std;
int read(){
	int nm=0,fh=1; char cw=getchar();
	for(;!isdigit(cw);cw=getchar()) if(cw=='-') fh=-fh;
	for(;isdigit(cw);cw=getchar()) nm=nm*10+(cw-'0');
	return nm*fh;
}
int s[M],n,m,p[M],cnt,rt[M],bf[M<<2],nt[M<<2],c[M<<2];
void ins(int pos,int dt){for(int k=pos;k<(M<<1);k=nt[k]) c[k]+=dt;}
int qry(int pos){int tt=0;for(int k=pos;k;k=bf[k]) tt+=c[k];return tt;}
LL solve(int Mid,int Min_len,int Max_len){
	LL res=0;
	memset(c,0,sizeof(c));
	for(int i=1;i<=n;i++){
		s[i]=(p[i]<=Mid?s[i-1]+1:s[i-1]-1);
		int t1=i-Max_len-1,t2=i-Min_len;
		if(t1>=0) ins(s[t1]+M,-1);
		if(t2>=0) ins(s[t2]+M,1); res+=qry(s[i]+M);
	}return res;
}
int main(){
	n=read();
	for(int i=1;i<(M<<2);i++) bf[i]=i-(i&-i),nt[i]=i+(i&-i);
	for(int i=1;i<=n;i++) p[i]=read();
	for(int T=read();T;--T){
		int l1=read(),r1=read(),l2=read(),r2=read();
		printf("%lld\n",solve(r1,l2,r2)-solve(l1-1,l2,r2));
	}
	return 0;
}

 

猜你喜欢

转载自www.cnblogs.com/OYJason/p/9900621.html