题目链接:hdu - 5517
题意
        
\;\;\;\;
一个多集(multi-set)
A
A
A 中含有
n
n
n 个二维元素
(
a
,
b
)
(a,b)
(a,b), 另一个多集
B
B
B 中含有
m
m
m 个三维元素
(
c
,
d
,
e
)
(c,d,e)
(c,d,e). 现定义多集
C
=
A
∗
B
=
{
(
a
,
c
,
d
)
∣
(
a
,
b
)
∈
A
,
(
c
,
d
,
e
)
∈
B
,
b
=
e
}
C = A * B = \left \{ (a,c,d) | (a,b) \in A, (c,d,e) \in B, b = e\right \}
C=A∗B={(a,c,d)∣(a,b)∈A,(c,d,e)∈B,b=e}.
        
\;\;\;\;
问:在集合C中,有多少个元素(a,c,d),满足:在多集
C
C
C 中,不存在另一个元素
(
u
,
v
,
w
)
≠
(
a
,
c
,
d
)
,
u
⩾
a
,
v
⩾
c
,
w
⩾
d
(u,v,w) \neq (a,c,d),u \geqslant a, v \geqslant c,w \geqslant d
(u,v,w)̸=(a,c,d),u⩾a,v⩾c,w⩾d.
1
≤
n
≤
1
0
5
,
1
≤
m
≤
1
0
5
,
1
≤
a
i
,
b
i
,
e
i
≤
1
0
5
,
1
≤
c
i
,
d
i
≤
1
0
3
1 \leq n \leq 10^{5}, 1 \leq m \leq 10^{5}, 1 \leq a_{i}, b_{i}, e_{i} \leq 10^{5}, 1 \leq c_{i}, d_{i} \leq 10^{3}
1≤n≤105,1≤m≤105,1≤ai,bi,ei≤105,1≤ci,di≤103.
思路
1.求集合
C
C
C 中元素
        
\;\;\;\;
集合
A
A
A 中元素与集合
B
B
B 中元素结合的条件,
b
=
e
b=e
b=e,而对于集合
A
A
A 中有着相同
b
b
b 的元素,对答案有贡献的只有
a
a
a 最大的那个元素;在输入集合
A
A
A 的过程中,记录每个
b
b
b 对应的最大的
a
a
a.
        
\;\;\;\;
在输入集合
B
B
B 的过程中,判断对于当前元素
(
c
,
d
,
e
)
(c,d,e)
(c,d,e) 的
e
e
e, 在集合
A
A
A 中是否存在一样的
b
b
b, 如果存在的话,向集合
C
C
C 中添加一个元素。
2.求满足条件的元素
        
\;\;\;\;
观察数据范围,发现集合
C
C
C 中,
a
a
a 的范围较大,
c
,
d
c,d
c,d 范围较小(这一定是在暗示什么)。
        
\;\;\;\;
可将集合
C
C
C 中的元素,按照
a
a
a 由大到小排序,维护一个
c
,
d
c,d
c,d 的二维树状数组, 每次查询
(
c
,
d
)
→
(
1
0
5
,
1
0
5
)
(c,d) \rightarrow (10^{5},10^{5})
(c,d)→(105,105) 点的数量,如果为
0
0
0 说明当前元素满足条件。
        
\;\;\;\;
按照
x
x
x 从小到大排序,维护一个关于坐标
y
y
y 的树状数组。遇见一个填充点操作
(
x
,
y
)
(x,y)
(x,y),就更新树状数组
u
p
d
a
t
e
(
y
,
z
)
update(y,z)
update(y,z),遇到一个查询操作,就加上或者减去前缀和
Q
u
e
r
y
(
y
−
1
)
Query(y-1)
Query(y−1).
        
\;\;\;\;
有个需要注意的点就是,集合
A
,
B
,
C
A,B,C
A,B,C 都是 multi-set,可以有重复元素,但是重复元素在最后的操作中又会产生麻烦的计算,所以,可以将相同的元素记录个数,留一个参与计算。
代码
/*
nero
2019-8-27 11:57:03
http://acm.hdu.edu.cn/showproblem.php?pid=5517
写代码之前看了别人的题解,感觉学到了好多,处理方法比我想的都好太多了,
学到了学到了 Orz
*/
#include <map>
#include <time.h>
#include <cmath>
#include <stack>
#include <queue>
#include <string>
#include <vector>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <bits/stdc++.h>
using namespace std;
#define lson(u) (u<<1)
#define rson(u) (u<<1|1)
#define Pi acos(-1)
#define iINF 0x3f3f3f3f
#define lINF 0x3f3f3f3f3f3f3f
#define EPS 0.000000001
#define pii pair<int, int>
typedef long long ll;
typedef unsigned long long ull;
const int MAXN = 1005;
int cc[MAXN][MAXN], Max[100005], Max_cnt[100005];
struct node {
int a, b, c;
ll num;
bool operator < (const node &C2) const {
if(a != C2.a) return a > C2.a;
if(b != C2.b) return b > C2.b;
return c > C2.c;
}
bool operator == (const node &C2) const {
if(a == C2.a && b == C2.b && c == C2.c) return 1;
else return 0;
}
}C[100005];
int lowbit(int x) {
return x & (-x);
}
void update(int x, int y) {
int i = x;
while(i < MAXN) {
int j = y;
while(j < MAXN) {
cc[i][j]++;
j += lowbit(j);
}
i += lowbit(i);
}
return;
}
int Query(int x, int y) {
int i = x;
int sum = 0;
while(i > 0) {
int j = y;
while(j > 0) {
sum += cc[i][j];
j -= lowbit(j);
}
i -= lowbit(i);
}
return sum;
}
int main()
{
int T;
scanf("%d", &T);
for(int tt = 1; tt <= T; tt++) {
int n, m;
int a, b, c, d, e;
memset(Max, 0, sizeof(Max));
int cnt = 0;
scanf("%d%d", &n, &m);
for(int i = 1; i <= n; i++) {
scanf("%d%d", &a, &b);
if(a > Max[b]) Max[b] = a, Max_cnt[b] = 1; // 去重 + 计数 *QQ*
else if(a == Max[b]) Max_cnt[b]++;
}
for(int i = 1; i <= m; i++) {
scanf("%d%d%d", &c, &d, &e);
if(Max[e]) {
C[++cnt] = node{Max[e], c, d, (ll)Max_cnt[e]}; // 匹配 *QQ*
}
}
sort(C + 1, C + cnt + 1);
int N = 1;
for(int i = 2; i <= cnt; i++) { // 去重 + 计数 *QQ*
if(C[i] == C[N]) C[N].num += C[i].num;
else C[++N] = C[i];
}
ll ans = 0;
memset(cc, 0, sizeof(cc));
for(int i = 1; i <= N; i++) {
int sum = Query(1001 - C[i].b, 1001 - C[i].c); // 求大 *QQ*
if(sum == 0) ans += C[i].num;
update(1001 - C[i]. b, 1001 - C[i].c); // 更新 *QQ*
}
printf("Case #%d: %lld\n", tt, ans);
}
return 0;
}