一.题目链接:
HDU-5213
二.题目大意:
有 n 组数,一个 k 值,m 次询问.
每次询问给出两个区间,求这两个区间内的数有多少组和为 k.
三.分析:
比较经典的莫队算法(奈何我第一次见)
莫队算法一般用来解决离线算法中的区间问题.
又被称为离线区间的万能解法(真是一个可啪的算法).
又因区间不连续,所以先要用容斥原理处理一下.
由容斥原理得:F(L1, R1, L2, R2) = F(L1, R2) - F(L1, L2 - 1) - F(R1 + 1, R2) + F(R1 + 1, L2 -1).
因此要开 4 * m 的结构体数组来存区间.
四.代码实现:
#include <set>
#include <map>
#include <ctime>
#include <queue>
#include <cmath>
#include <stack>
#include <vector>
#include <cstdio>
#include <sstream>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#define eps 1e-4
#define PI acos(-1.0)
#define ll long long int
using namespace std;
const int M = 30000 + 5;
int cnt[M];
int a[M];
int res[M];
int block;
struct node
{
int l, r;
int id;
int f;
} s[M << 2];
int cmp(node a, node b)
{
if(a.l / block != b.l / block)
return a.l / block < b.l / block;
return a.r < b.r;
}
void modui(int n, int m, int k)
{
int l, r;
l = r = 1;
int ans = 0;
for(int i = 0; i < m; ++i)
{
while(r < s[i].r)
{
r++;
if(k > a[r] && k - a[r] <= n)
ans += cnt[k-a[r]];
cnt[a[r]]++;
}
while(r > s[i].r)
{
cnt[a[r]]--;
if(k > a[r] && k - a[r] <= n)
ans -= cnt[k-a[r]];
r--;
}
while(l < s[i].l)
{
cnt[a[l]]--;
if(k > a[l] && k - a[l] <= n)
ans -= cnt[k-a[l]];
l++;
}
while(l > s[i].l)
{
l--;
if(k > a[l] && k - a[l] <= n)
ans += cnt[k-a[l]];
cnt[a[l]]++;
}
res[s[i].id] += ans * s[i].f;
}
}
int main()
{
int n;
while(~scanf("%d", &n))
{
memset(res, 0, sizeof(res));
memset(cnt, 0, sizeof(cnt));
block = (int)sqrt(n + 0.5);
int k;
scanf("%d", &k);
for(int i = 1; i <= n; ++i)
{
cnt[i] = 0;
scanf("%d", &a[i]);
}
int m;
scanf("%d", &m);
for(int i = 0; i < m; ++i)
{
int l1, r1;
int l2, r2;
scanf("%d %d %d %d", &l1, &r1, &l2, &r2);
int pos = i << 2;
s[pos].l = l1, s[pos].r = r2, s[pos].id = i, s[pos].f = 1;
s[pos + 1].l = l1, s[pos + 1].r = l2 - 1, s[pos + 1].id = i, s[pos + 1].f = -1;
s[pos + 2].l = r1 + 1, s[pos + 2].r = r2, s[pos + 2].id = i, s[pos + 2].f = -1;
s[pos + 3].l = r1 + 1, s[pos + 3].r = l2 - 1, s[pos + 3].id = i, s[pos + 3].f = 1;
}
sort(s, s + m * 4, cmp);
modui(n, m * 4, k);
for(int i = 0; i < m; ++i)
printf("%d\n", res[i]);
}
return 0;
}