给出n个数,给出m个询问,询问 区间[l,r] [u,v],在两个区间内分别取一个数,两个的和为k的对数数量。
$k<=2*N$,$n <= 30000$
发现可以容斥简化一个询问。一个询问的答案为 $[l,v]+(r,u)-[l,u)-(r,v]$,那么我们离线询问,将一个询问分成四个,分块暴力就行了。
然后就是注意细节,不要发生越界,访问错位置之类比较蠢的问题了。
/** @Date : 2017-09-24 19:54:55 * @FileName: HDU 5213 分块 容斥.cpp * @Platform: Windows * @Author : Lweleth (SoungEarlf@gmail.com) * @Link : https://github.com/ * @Version : $Id$ */ #include <bits/stdc++.h> #define LL long long #define PII pair<int ,int> #define MP(x, y) make_pair((x),(y)) #define fi first #define se second #define PB(x) push_back((x)) #define MMG(x) memset((x), -1,sizeof(x)) #define MMF(x) memset((x),0,sizeof(x)) #define MMI(x) memset((x), INF, sizeof(x)) using namespace std; const int INF = 0x3f3f3f3f; const int N = 1e5 + 20; const double eps = 1e-8; int a[30010]; int blc[30010]; struct yuu { int l, r, idx, f; yuu() {} inline yuu(int _l, int _r, int i, int _f): l(_l), r(_r), idx(i), f(_f) {} } b[120010];//明明是RE 报的TLE 有毒啊? LL ans[30010]; LL vis[30010]; inline int cmp(yuu a, yuu b) { if(blc[a.l] != blc[b.l]) return a.l < b.l; return a.r < b.r; } int main() { int n, k; while(~scanf("%d%d", &n, &k)) { int sqr = sqrt(n * 1.0); for(int i = 1; i <= n; i++) scanf("%d", a + i), blc[i] = (i - 1) / sqr + 1; int m; scanf("%d", &m); for(int i = 0; i < m; i++) { int l, r, u, v; scanf("%d%d%d%d", &l, &r, &u, &v); b[i * 4] = yuu(l, v, i, 1); b[i * 4 + 1] = yuu(r + 1, u - 1, i, 1); b[i * 4 + 2] = yuu(l, u - 1, i, -1); b[i * 4 + 3] = yuu(r + 1, v, i, -1); } sort(b, b + m * 4, cmp); MMF(ans); MMF(vis); LL t = 0; int l = 1, r = 0; for(int i = 0; i < m * 4; i++) { while(r < b[i].r) { r++; vis[a[r]]++; if(k - a[r] > 0 && k - a[r] <= n)//小于n t += vis[k - a[r]]; } while(l > b[i].l) { l--; vis[a[l]]++; if(k - a[l] > 0 && k - a[l] <= n) t += vis[k - a[l]]; } while(r > b[i].r) { if(k - a[r] > 0 && k - a[r] <= n) t -= vis[k - a[r]]; vis[a[r]]--; r--; } while(l < b[i].l) { if(k - a[l] > 0 && k - a[l] <= n) t -= vis[k - a[l]]; vis[a[l]]--; l++; } ans[b[i].idx] += t * b[i].f; //cout << t << b[i].l << b[i].r << endl; } for(int i = 0; i < m; i++) printf("%lld\n", ans[i]); } return 0; } //
原文:http://www.cnblogs.com/Yumesenya/p/7589320.html