링크 :
https://vjudge.net/contest/308446#problem/C
질문의 의미 :
치카는 당신에게 정수 순서 A1, A2, ...,를 사용하며 m 작업을 제공합니다. 각 작업의 경우, 지정된 간격으로 "친숙한 쌍"의 수에 답해야합니다.
친화 쌍 두 정수 A1 및 AJ가 나는 J를 <및 인공 AJ의 절대 값이 K가 다음 (I, J)는 "친화적 쌍".A 친화적 쌍 (이라고 주어진 일정한 정수 이하이면 간격 [L, R]의 I, J)는 L≤i <j≤R을 만족한다.
아이디어 :
모 알고리즘 팀 단지 모 팀, 제 질의 각 변화 위치를 학습 바보.
두 배열 첨자 각 위치 조회 기록. 시간 오버 헤드를 줄인다.
코드 :
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 3e4+10;
struct Node
{
int l, r;
int pos;
}node[MAXN];
int Tree[MAXN];
int a[MAXN], b[MAXN];
int L[MAXN], R[MAXN], P[MAXN];
int Res[MAXN];
int n, m, k;
int pos;
int l, r, res;
int unit;
int Lowbit(int x)
{
return (-x)&x;
}
void AddTree(int x, int v)
{
while (x <= n)
{
Tree[x] += v;
x += Lowbit(x);
}
}
int GetSum(int x)
{
int sum = 0;
while (x > 0)
{
sum += Tree[x];
x -= Lowbit(x);
}
return sum;
}
void Add(int x)
{
int rsum = GetSum(R[x]);
int lsum = GetSum(L[x]);
res += rsum-lsum;
AddTree(P[x], 1);
}
void Del(int x)
{
AddTree(P[x], -1);
int rsum = GetSum(R[x]);
int lsum = GetSum(L[x]);
res -= rsum - lsum;
}
void Query(int ql, int qr)
{
while (l < ql)
Del(l++);
while (l > ql)
Add(--l);
while (r < qr)
Add(++r);
while (r > qr)
Del(r--);
}
bool cmp(Node& a, Node& b)
{
if (a.l/unit != b.l/unit)
return a.l/unit < b.l/unit;
return a.r < b.r;
}
int main()
{
scanf("%d %d %d", &n, &m, &k);
unit = sqrt(n);
for (int i = 1;i <= n;i++)
{
scanf("%d", &a[i]);
b[i] = a[i];
}
for (int i = 1;i <= m;i++)
scanf("%d %d", &node[i].l, &node[i].r), node[i].pos = i;
sort(b+1, b+1+n);
pos = unique(b+1, b+1+n)-b;
for (int i = 1;i <= n;i++)
{
P[i] = lower_bound(b+1, b+pos, a[i])-b;
R[i] = lower_bound(b+1, b+pos, a[i]+k)-b;
if (b[R[i]] != a[i]+k)
R[i]--;
L[i] = lower_bound(b+1, b+pos, a[i]-k)-b-1;
}
sort(node+1, node+1+m, cmp);
l = 1, r = 0;
for (int i = 1;i <= m;i++)
{
Query(node[i].l, node[i].r);
Res[node[i].pos] = res;
}
for (int i = 1;i <= m;i++)
printf("%d\n", Res[i]);
return 0;
}
/*
7 2 3
2 5 7 5 1 5 6
6 6
1 3
4 6
2 4
3 4
7 2 3
2 5 7 5 1 5 6
1 3
4 6
*/