HDU 5517 【二维树状数组///三维偏序问题】
题目链接:【http://acm.split.hdu.edu.cn/showproblem.php?pid=5517】
题意:定义multi_set A<a , d>,B<c , d , e>,C<x , y , z>,给出 A , B ,定义 C = A * B = ={⟨a,c,d⟩∣⟨a,b⟩∈A, ⟨c,d,e⟩∈B and b=e} 。求出C之后,求C中一个元素t[i]<a , b , c>是否存在一个元素tmp<x , y , z>使得 x >= a&&y > =b&&z >= c && t != tmp;如果不存在ans++;输出ans即可。
题解:
首先,我们要剪枝和去重,加入集合A中存在<1 , 3>,<2, 3>,<3, 3> ,<4, 3>,<4, 3>,那么只需要保留<4,3>就可以了,并且记录一下数量。因为前面的数都可以找到比它大的元素。求出C之后,我们依旧要对C去重。那么这道题就是求C某个元素是否存在大于它的元素了。因为这道题中B set里面c,d,很小在生成的C中y,z也很小,都小于1000,那么我们就可以用二维树状数组做了。首先对C进行从大到小排序,树状数组中只记录y,z的值。我们枚举C中的额每一个元素,先查询(1001 - y ,1001 - z),然后在更新(1001 - y ,1001 - z),应为是从大到小排序的,所以后面的元素的x值一定小于等于前面的元素的x值,s如果查询不为0,那么一定存在某个元素是大于它的。我们一可以直接套CDQ分治的三维偏序模板,为维护值即可。
树状数组:
#include<bits/stdc++.h> using namespace std; typedef long long LL; const int maxn = 1e5 + 15; int ic, N, M; struct Point { int x, y, z; LL w; Point() {} Point(int x, int y, int z, LL w): x(x), y(y), z(z), w(w) {} bool operator < (const Point& T) const { if(x != T.x) return T.x < x; if(y != T.y) return T.y < y; return T.z < z; } bool operator == (const Point T) const { return (x == T.x && y == T.y && z == T.z); } } P[maxn]; int T[maxn], C[maxn]; int Tbit[1050][1050]; int low_bit(int x) { return x & -x; } void Bit_add(int x, int y, int val) { for(int i = x; i <= 1001; i += low_bit(i)) for(int j = y; j <= 1001; j += low_bit(j)) Tbit[i][j] += val; } int Bit_sum(int x, int y) { int ret = 0; for(int i = x; i; i -= low_bit(i)) for(int j = y; j; j -= low_bit(j)) ret += Tbit[i][j]; return ret; } int main () { scanf("%d", &ic); for(int cs = 1; cs <= ic; cs++) { scanf("%d %d", &N, &M); memset(T, 0, sizeof(T)); for(int i = 1; i <= N; i++) { int a, b; scanf("%d %d", &a, &b); if(a > T[b]) T[b] = a, C[b] = 1; else if(a == T[b]) C[b]++; } int tmp = 0; for(int i = 1; i <= M; i++) { int a, b, c; scanf("%d %d %d", &a, &b, &c); if(T[c]) P[++tmp] = Point(T[c], a, b, (LL)C[c]); } sort(P + 1, P + 1 + tmp); N = 1; for(int i = 2; i <= tmp; i++) { if(P[i] == P[N]) P[N].w += P[i].w; else P[++N] = P[i]; } LL ans = 0; memset(Tbit, 0, sizeof(Tbit)); for(int i = 1; i <= N; i++) { if(!Bit_sum(1001 - P[i].y, 1001 - P[i].z)) ans += P[i].w; Bit_add(1001 - P[i].y, 1001 - P[i].z, 1); } printf("Case #%d: %lld\n", cs, ans); } return 0; }
三维偏序:
#include <bits/stdc++.h> using namespace std; typedef long long LL; const int maxn = 1e5 + 15; int cs, N, M; int T[maxn], C[maxn]; LL W[maxn], ans[maxn]; struct Edge { int x, y, z, id; LL w; Edge() {} Edge(int x, int y, int z, int id, LL w): x(x), y(y), z(z), id(id), w(w) {} bool operator < (const Edge & T) const { return z < T.z; } bool operator == (const Edge & T) const { return T.x == x && T.y == y && T.z == z; } } B[maxn], p[maxn], t[maxn]; bool cmpx(Edge &a, Edge &b) { if(a.x == b.x && a.y == b.y && a.z == b.z) return a.id < b.id; else if(a.x == b.x && a.y == b.y) return a.z < b.z; else if(a.x == b.x) return a.y < b.y; else return a.x < b.x; } bool cmpy(Edge &a, Edge &b) { if( a.y == b.y && a.z == b.z) return a.id < b.id; else if(a.y == b.y) return a.z < b.z; else return a.y < b.y; } //--------------------------------------------------------//树状数组 int c[maxn], maxz = 1001; inline int lowbit(int x) { return x & (-x); } void add(int x, int val) { while(x <= maxz) c[x] += val, x += lowbit(x); } int Get_sum(int x) { int ret = 0; while(x > 0) ret += c[x], x -= lowbit(x); return ret; } //------------------------------------------------- void cdq(int l, int r) { if(l == r) return ; int mid = (l + r) / 2; cdq(l, mid), cdq(mid + 1, r); for(int i = l; i <= r; i++) t[i] = p[i]; sort(t + l, t + mid + 1, cmpy), sort(t + mid + 1, t + r + 1, cmpy); int a1 = l, a2 = mid + 1; for(int i = l; i <= r; i++) { if(a1 == mid + 1) ans[t[a2].id] += Get_sum(t[a2].z), a2++; else if(a2 == r + 1) add(t[a1].z, 1), a1++; else if(t[a1].y <= t[a2].y) add(t[a1].z, 1), a1++; else ans[t[a2].id] += Get_sum(t[a2].z), a2++; } for(int i = l; i <= mid; i++) add(t[i].z, -1); } int main () { scanf("%d", &cs); for(int ic = 1; ic <= cs; ic++) { memset(T, 0, sizeof(T)); memset(ans, 0, sizeof(ans)); scanf("%d %d", &N, &M); for(int i = 1; i <= N; i++) { int a, b; scanf("%d %d", &a, &b); if(a > T[b]) T[b] = a, C[b] = 1; else if(a == T[b]) C[b]++; } int tmp = 0; for(int i = 1; i <= M; i++) { int a, b, c; scanf("%d %d %d", &a, &b, &c); if(T[c]) ++tmp, p[tmp] = Edge(T[c], a, b, i, (LL)C[c]); } sort(p + 1, p + 1 + tmp, cmpx); N = 1; for(int i = 2; i <= tmp; i++) { if(p[i] == p[N]) p[N].w += p[i].w; else p[++N] = p[i]; } if(N <= 1) { printf("Case #%d: 0\n", ++ic); continue; } for(int i = 1; i <= N; i++) { p[i].x = 100001 - p[i].x; p[i].y = 1001 - p[i].y; p[i].z = 1001 - p[i].z; } for(int i = 1; i <= N; i++) { p[i].id = i; W[i] = p[i].w; } sort(p + 1, p + 1 + N, cmpx); cdq(1, N); p[N + 1].x = -1; for(int i = N; i >= 1; i--) { if(p[i].x == p[i + 1].x && p[i].y == p[i + 1].y && p[i].z == p[i + 1].z) ans[p[i].id] = ans[p[i + 1].id]; } LL ret = 0; for(int i = 1; i <= N; i++) if(!ans[i]) ret += W[i]; printf("Case #%d: %lld\n", ic, ret); } return 0; }
想的太多,做的太少。