Triple+预处理+二维树状数组

https://blog.youkuaiyun.com/DERITt/article/details/51201535

 

对于二元组(a,b),b相同的话只有最大的a值有效,所以对相同的b记录一下最大值的个数。
对于三元组(c,d,e),对于相同的e,先按照c排序,对于c相同的三元组,只有最大的d有效,对于c不同的三元组,一个三元组的(c,d,e)有效的话,只有它的d只大于所有c值比它大的三元组的d值,所以扫一遍记录最大值就能知道哪些三元组有效。最后得到很多拼接成的三元组(a,c,d)和它们个数,按第一维排序扫一遍,用树状数组记录最大值就能nlogn搞了

 

Given the finite multi-set A of n pairs of integers, an another finite multi-set B of m triples of integers, we define the product of A and B as a multi-set

C=A∗B={〈a,c,d〉∣〈a,b〉∈A, 〈c,d,e〉∈B and b=e}

For each 〈a,b,c〉∈C, its BETTER set is defined as

BETTERC(〈a,b,c〉)={〈u,v,w〉∈C∣〈u,v,w〉≠〈a,b,c〉, u≥a, v≥b, w≥c}

As a \textbf{multi-set} of triples, we define the TOP subset (as a multi-set as well) of C, denoted by TOP(C), as

TOP(C)={〈a,b,c〉∈C∣BETTERC(〈a,b,c〉)=∅}

You need to compute the size of TOP(C)

.

Input

The input contains several test cases. The first line of the input is a single integer t (1≤t≤10)

which is the number of test case. Then t test cases follow.

Each test case contains three lines. The first line contains two integers n (1≤n≤105) and m (1≤m≤105) corresponding to the size of A and B respectively.
The second line contains 2×n nonnegative integers

a1,b1,a2,b2,⋯,an,bn


which describe the multi-set A, where 1≤ai,bi≤105.
The third line contains 3×m nonnegative integers

c1,d1,e1,c2,d2,e3,⋯,cm,dm,em


corresponding to the m triples of integers in B, where 1≤ci,di≤103 and 1≤ei≤105

.

Output

For each test case, you should output the size of set TOP(C)

.

Sample Input

2
5 9
1 1 2 2 3 3 3 3 4 2
1 4 1 2 2 1 4 1 1 1 3 2 3 2 2 4 1 2 2 4 3 3 2 3 4 1 3
3 4
2 7 2 7 2 7
1 4 7 2 3 7 3 2 7 4 1 7

Sample Output

Case #1: 5
Case #2: 12
#include <cstdio>
#include <cstring>
#include <vector>
#include <algorithm>

using namespace std;
const int maxn = 1e5 + 5;
typedef long long ll;
#define lowbit(x) ((x)&(-x))

struct Point {
    int x, y, z;
    ll w;
    Point(int x = 0, int y = 0, int z = 0, ll w = 0): x(x), y(y), z(z), w(w) {}
    bool operator < (const Point& u) const { 
        if (x != u.x) return x < u.x;
        if (y != u.y) return y < u.y;
        return z < u.z;
    }
    bool operator == (const Point& u) const { return !((*this)<u || u<(*this)); }
};

int N, M, T[maxn], C[maxn];
Point P[maxn];

void init () {
    scanf("%d%d", &N, &M);
    memset(T, 0, sizeof(T));

    int a, b, c;
    for (int i = 0; i < N; i++) {
        scanf("%d%d", &a, &b);
        if (a > T[b]) { T[b] = a, C[b] = 0; }
        if (a == T[b]) C[b]++;
    }

    int n = 0;
    for (int i = 0; i < M; i++) {
        scanf("%d%d%d", &a, &b, &c);
        if (T[c])
            P[n++] = Point(T[c], a, b, C[c]);
    }

    sort(P, P + n);
    N = 0;
    for (int i = 1; i < n; i++) {
        if (P[i] == P[N]) P[N].w += P[i].w;
        else P[++N] = P[i];
    }
}

ll fenw[1005][1005];

void add(int x, int y, ll v) {
    for (int i = x; i <= 1000; i += lowbit(i)) {
        for (int j = y; j <= 1000; j += lowbit(j)) 
            fenw[i][j] += v;
    }
}

ll sum(int x, int y) {
    int ret = 0;
    for (int i = x; i; i -= lowbit(i)) {
        for (int j = y; j; j -= lowbit(j))
            ret += fenw[i][j];
    }
    return ret;
}

ll query(int x1, int y1, int x2, int y2) {
    return sum(x2, y2) - sum(x2, y1-1) - sum(x1-1, y2) + sum(x1-1, y1-1);
}

ll solve () {
    ll ans = 0;
    memset(fenw, 0, sizeof(fenw));

    for (int i = N; i >= 0; i--) {
        if (!query(P[i].y, P[i].z, 1000, 1000))
            ans += P[i].w;
        add(P[i].y, P[i].z, 1);
    }
    return ans;
}

int main () {
    int cas;
    scanf("%d", &cas);
    for (int kcas = 1; kcas <= cas; kcas++) {
        init();
        printf("Case #%d: %lld\n", kcas, solve());
    }
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值