5 3 1 2 1 2 3 1 1 2 3 5
2Hinta1+a4=a2+a3=3=K. So we have two pairs of numbers (1,4) and (2,3). Good luck!
题意:求某个给定一个数列和k,每次询问两个区间(没有交集)和等于k的二元对数.
假设f(a,b)表示区间a,b中和等于k的二元对数,F(a,b,c,d)表示询问,那么根据容斥原
理F(a,b,c,d) = f(a,d)-f(a,c-1)-f(b+1,d)+f(b+1,c-1).然后对于f函数的值很容易用莫队
搞了.所以把每一个F询问都拆成4个f询问,然后就可以用莫队了.
#include <bits/stdc++.h> using namespace std; #define maxn 121111 int pos[maxn]; int n, m, k; long long cnt[maxn]; long long ans[maxn], tmp[maxn]; struct node { int l, r, id; bool operator < (const node &a) const { return pos[l] < pos[a.l] || (pos[l] == pos[a.l] && r < a.r); } long long ans; } p[maxn]; int a[maxn]; long long cur; bool cmp (const node &a, const node &b) { return a.id < b.id; } void add (int pos) { if (k-a[pos] >= 0) cur += cnt[k-a[pos]]; cnt[a[pos]]++; } void del (int pos) { cnt[a[pos]]--; if (k-a[pos] >= 0) cur -= cnt[k-a[pos]]; } int main () { //freopen ("in.txt", "r", stdin); while (scanf ("%d", &n) == 1) { scanf ("%d", &k); a[0] = 0; for (int i = 1; i <= n; i++) { scanf ("%d", &a[i]); } int block = ceil (sqrt (n*1.0)); for (int i = 1; i <= n; i++) pos[i] = (i-1)/block; scanf ("%d", &m); int tot = 0; for (int i = 0; i < m; i++) { int a, b, c, d; scanf ("%d%d%d%d", &a, &b, &c, &d); p[tot] = (node) {a, d, tot, 0}; tot++; p[tot] = (node) {a, c-1, tot, 0}; tot++; p[tot] = (node) {b+1, d, tot, 0}; tot++; p[tot] = (node) {b+1, c-1, tot, 0}; tot++; } sort (p, p+tot); int l = 1, r = 1; cur = 0; memset (cnt, 0, sizeof cnt); add (1); for (int i = 0; i < tot; i++) { if (p[i].l > p[i].r) { p[i].ans = 0; continue; } while (r > p[i].r) { del (r); r--; } while (r < p[i].r) { r++; add (r); } while (l > p[i].l) { l--; add (l); } while (l < p[i].l) { del (l); l++; } p[i].ans = cur; } sort (p, p+tot, cmp); for (int i = 0; i < m; i++) { printf ("%lld\n", p[i<<2].ans-p[(i<<2)+1].ans-p[(i<<2)+2].ans+p[(i<<2)+3].ans); } } return 0; }