序列 - BIT

题目大意:
给你一个序列,问有多少长度在[L2,R2]子区间的中位数在[L1,R1]之间。
题解:
这个中位数是可以差分的[1,R1]-[1,L1)。
solve(x)。将<=x看做1,其余看做-1。
然后根据区间长度奇偶性判定为区间前缀和>0或者>=0。
扫描线+树状数组即可。(其实算不上扫描线)。

#include<bits/stdc++.h>
#define gc getchar()
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define Rep(i,v) rep(i,0,(int)v.size()-1)
#define lint long long
#define N 100010
#define db long double
#define pb push_back
#define mp make_pair
#define fir first
#define sec second
#define debug(x) cerr<<#x<<"="<<x
#define sp <<" "
#define ln <<endl
using namespace std;
typedef pair<int,int> pii;
typedef set<int>::iterator sit;
inline int inn()
{
	int x,ch;while((ch=gc)<'0'||ch>'9');
	x=ch^'0';while((ch=gc)>='0'&&ch<='9')
		x=(x<<1)+(x<<3)+(ch^'0');return x;
}
#define lb(x) (x&-x)
int ql1[N],qr1[N],ql2[10],qr2[10],a[N],T[2][N],s[N];
inline int upd(int *b,int p,int n,int v) { for(;p<=n;p+=lb(p)) b[p]+=v;return 0; }
inline int query(int *b,int p) { int ans=0;for(;p;p-=lb(p)) ans+=b[p];return ans; }
inline lint calc(int x,int n,int L,int R)
{
	s[0]=0;rep(i,1,n) s[i]=s[i-1]+(a[i]<=x?1:-1);
	int bs=1;rep(i,1,n) bs=max(bs,-s[i]+1);
	lint ans=0;
	memset(T[0],0,sizeof(int)*(n+2));
	memset(T[1],0,sizeof(int)*(n+2));
	rep(i,1,n)
	{
		if(i-R-1>=0) upd(T[(i-R-1)&1],s[i-R-1]+bs,n+1,-1);
		if(i-L>=0) upd(T[(i-L)&1],s[i-L]+bs,n+1,1);
		ans+=query(T[i&1],s[i]+bs);
		ans+=query(T[(i&1)^1],s[i]-1+bs);
	}
	return ans;
}
int main()
{
	int n=inn();rep(i,1,n) a[i]=inn();int m=inn();
	rep(i,1,m) ql1[i]=inn(),qr1[i]=inn(),ql2[i]=inn(),qr2[i]=inn();
	rep(i,1,m) printf("%lld\n",calc(qr1[i],n,ql2[i],qr2[i])-calc(ql1[i]-1,n,ql2[i],qr2[i]));
	return 0;
}

猜你喜欢

转载自blog.csdn.net/Mys_C_K/article/details/83685658
BIT