Chika and Friendly Pairs (2019 GDCPC 广东省赛银牌题)(离散化+莫队+树状数组)

题意

给出一个含有n个元素的数列a和k值,询问m次,每次询问给出L,R,输出[L,R]中friendly pair的总个数。

friendly pair:对于数列位置i < j,有丨 a[i] - a[j] 丨<= k,则相当于一个friendly pair

输入数据

第一行3个整数n(1 <= n <= 27000),m(1 <= n <= 27000), k(1 <= n <= 1e9)

第二行n个整数表示数列a,每个整数不超过1e9

接下来m行表示m个询问,每行两个整数L,R

输入案例

7 5 3
2 5 7 5 1 5 6
6 6
1 3
4 6
2 4
3 4

输出案例

0

2

1

3

1

 

现场情况

当时只想到了莫队和树状数组,但是却没有离散化,而是用map数组储存,导致了时间复杂度为(n*√n*logn*logn),相对于正解多了个logn,导致无限TLE而铜牌,心塞了,就差一点点啊!

思路

需要离散化,将数列的所有元素及其+k,-k离散化,这样使用树状数组时便不需要用到map而导致时间复杂度多了个logn。

莫队就不多说了,而树状数组的思路,类似于树状数组求逆序数。

下面是赛后写的代码,由于没有数据测试,不保证代码正确性,时间复杂度(n*√n*logn)

#include 
#define ll long long
using namespace std;
const int maxn = 27010;
struct node{
	int l,r,id;
}que[maxn];
int a[maxn];
int b[maxn*3];
int ans[maxn];
int sum[maxn*3];
int size,limit,n,m,k;
map mp;
void add(int p, int x){ //给位置p增加x
    while(p <= size) sum[p] += x, p += p & -p;
}
int ask(int p){ //求位置p的前缀和
    int res = 0;
    while(p) res += sum[p], p -= p & -p;
    return res;
}
int range_ask(int l, int r){ //区间求和
    return ask(r) - ask(l - 1);
}
bool cmp(node x,node y){
	if(x.l/limit == y.l/limit)
		return x.r < y.r;
	return x.l/limit < y.l/limit;
}
void solve()
{
	int L,R,ans1;
	L = R = 1;
	ans1 = 0;
	add(mp[a[1]],1);
	for(int i = 1;i <= m;i++)
	{
		while(que[i].l > L)
		{
			add(mp[a[L]],-1);
			ans1-=range_ask(mp[a[L]-k],mp[a[L]+k]);
			L++;
		}
		//减
		while(que[i].r < R)
		{
			add(mp[a[R]],-1);
			ans1-=range_ask(mp[a[R]-k],mp[a[R]+k]);
			R--;
		}
		//减
		while(que[i].l < L)
		{
			L--;
			ans1+=range_ask(mp[a[L]-k],mp[a[L]+k]);
			add(mp[a[L]],1);
		}
		//加
		while(que[i].r > R)
		{
			R++;
			ans1+=range_ask(mp[a[R]-k],mp[a[R]+k]);
			add(mp[a[R]],1);
		}
		//加
		ans[que[i].id] = ans1;
	}
	for(int i = 1;i <= m;i++)
		printf("%d\n",ans[i]);
}
int main(){
	while(~scanf("%d%d%d",&n,&m,&k)){
		memset(sum,0,sizeof(sum));
		limit = (int)(sqrt(n)+0.5);
		mp.clear();
		for(int i = 1,j = 1;i <= n;i++){
			scanf("%d",&a[i]);
			b[j++] = a[i];
			b[j++] = a[i]+k;
			b[j++] = a[i]-k;
		}
		for(int i = 1;i <= m;i++){
			scanf("%d%d",&que[i].l,&que[i].r);
			que[i].id = i;
		}
		sort(b+1,b+1+3*n);
		sort(que+1,que+1+m,cmp);
		size = unique(b+1,b+1+3*n)-b-1;
		for(int i = 1;i <= size;i++){
			mp[b[i]] = i;
		}
		solve();
	}
	return 0;
}
/*
7 5 3
2 5 7 5 1 5 6
6 6
1 3
4 6
2 4
3 4
*/

 

你可能感兴趣的:(数组,区间)