(HDU) 6534 Chika and Friendly Pairs (莫队+树状数组)

5 篇文章 0 订阅
2 篇文章 0 订阅

传送门

题意:

给你一个数组,对于第i个数来说,如果存在一个位置j,使得j>i并且a[j]-k<=a[i]<=a[j]+k,那么这对数就称为好的,有q个询问,问你l到r区间有多少对好的数。

思路:

这题卡常数卡的好厉害呀,比赛时是用主席树+莫队写的gg,主席数常数太大了,用树状数组和莫队维护,同时先把a[i],a[i]-k,a[i]+k先全部离散好了。

#include<bits/stdc++.h>
#define il inline
#define pb push_back
#define fi first
#define se second
#define ms(_data,v) memset(_data,v,sizeof(_data))
#define sc(n) scanf("%d",&n)
#define SC(n,m) scanf("%d %d",&n,&m)
#define SZ(a) int((a).size())
#define rep(i,a,b) for(int i=a;i<=b;++i)
#define drep(i,a,b)	for(int i=a;i>=b;--i)
using namespace std;
typedef long long ll;
const ll inf=0x3f3f3f3f;
const double PI=acos(-1.0);
const double eps=1e-9;
const int maxn=3e4+5;
int sum[maxn<<2],n,m,k;
int a[maxn],b[maxn<<2];
//树状数组 
il void add(int p,int x) {
	while(p<=3*n+10) sum[p]+=x,p+=p&-p;
}
il int ask(int p) {
	int res=0;
	while(p) res+=sum[p],p-=p&-p;
	return res;
}
il int r_ask(int l,int r) {
	return ask(r)-ask(l-1);
}
//莫队
struct node {
	int id,l,r;
} qu[maxn];
int block,res=0,ans[maxn];
il bool cmp(node x,node y) {
	if(x.l/block != y.l/block)	return x.l<y.l;
	else return x.r<y.r;
}
int ida[maxn],upa[maxn],doa[maxn];
int main() {
	std::ios::sync_with_stdio(0);
	sc(n),sc(m),sc(k);
	int cnt=0;
	rep(i,1,n) {
		sc(a[i]);
		b[++cnt]=a[i],b[++cnt]=a[i]-k,b[++cnt]=a[i]+k;
	}
	sort(b+1,b+cnt+1);
	int sz=unique(b+1,b+cnt+1)-(b+1);
	rep(i,1,n) {
		ida[i]=lower_bound(b+1,b+sz+1,a[i])-b;
		upa[i]=lower_bound(b+1,b+sz+1,a[i]+k)-b;
		doa[i]=lower_bound(b+1,b+sz+1,a[i]-k)-b;
	}
	rep(i,1,m)	SC(qu[i].l,qu[i].r),qu[i].id=i;
	block=sqrt(n);
	sort(qu+1,qu+m+1,cmp);
	int L=qu[1].l,R=qu[1].l-1;
	rep(i,1,m) {
		while(L<qu[i].l) {
			add(ida[L],-1);
			res-=r_ask(doa[L],upa[L]);
			L++;
		}
		while(L>qu[i].l) {
			L--;
			res+=r_ask(doa[L],upa[L]);
			add(ida[L],1);
		}
		while(R>qu[i].r) {
			add(ida[R],-1);
			res-=r_ask(doa[R],upa[R]);
			R--;
		}
		while(R<qu[i].r) {
			R++;
			res+=r_ask(doa[R],upa[R]);
			add(ida[R],1);
		}
		ans[qu[i].id]=res;
	}

	rep(i,1,m)	printf("%d\n",ans[i]);
	return 0;
}


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值