题目大意:给定一个二元组集合A{<a, b>}, 一个三元组集合B{<c, d, e>}, 定义 C 为 A 和 B 在 {b = e} 上的连接,求 C 集合中凸点的个数,即:最值点的个数。

题解:

C 为一个三元组集合,求凸点的个数问题等价于三维偏序问题,去重之后可以直接计算。

不过,发现若直接暴力进行连接运算,最坏情况下会产生 \(O(NM)\) 个 C 元组,时间和空间无法承受。发现对于 A 中同一个 b 值的所有二元组来说,只有最大的 a 值才可能对答案产生贡献。因此,考虑对于每一个 b,都找到一个最大的 a 以及对应元组的数量。这样,对于每一个 B 中的元组来说,至多只有一个 A 中的元组与之对应,即:C 中的合法元素至多只有 \(O(M)\) 个,答案的上界也是 M。

本题中的 c, d 值域较小,因此,可以直接利用二维树状数组进行维护,即:对 a 排序,并用树状数组维护 c, d 即可。

注意:三位偏序问题一定要去重。

代码如下

#include <bits/stdc++.h>

using namespace std;

struct A {
int a, b;
};
struct B {
int c, d, e;
};
struct C {
int a, c, d, cnt;
C(int x, int y, int z, int w) {
a = x, c = y, d = z, cnt = w;
}
friend bool operator==(const C &x, const C &y) {
return x.a == y.a && x.c == y.c && x.d == y.d;
}
}; struct fenwick {
vector<vector<int>> t;
int n;
fenwick(int _n) {
n = _n;
t.resize(_n + 1, vector<int>(_n + 1));
}
void modify(int x, int y, int val) {
for (int i = x; i <= n; i += i & -i) {
for (int j = y; j <= n; j += j & -j) {
t[i][j] += val;
}
}
}
int query(int x, int y) {
int ret = 0;
for (int i = x; i; i -= i & -i) {
for (int j = y; j; j -= j & -j) {
ret += t[i][j];
}
}
return ret;
}
int get(int x, int y) {
return query(n, n) - query(n, y - 1) - query(x - 1, n) + query(x - 1, y - 1);
}
}; int main() {
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
int T, kase = 0;
cin >> T;
while (T--) {
int n, m, range = 0, fen_size = 0;
cin >> n >> m;
vector<A> a(n); // a, b
vector<B> b(m); // c, d, e
for (int i = 0; i < n; i++) {
cin >> a[i].a >> a[i].b;
range = max(range, a[i].b);
}
for (int i = 0; i < m; i++) {
cin >> b[i].c >> b[i].d >> b[i].e;
range = max(range, b[i].e);
fen_size = max(fen_size, max(b[i].c, b[i].d));
}
vector<pair<int, int>> maxa(range + 1); // maxa, cnt
for (int i = 0; i < n; i++) {
if (a[i].a > maxa[a[i].b].first) {
maxa[a[i].b].first = a[i].a;
maxa[a[i].b].second = 1;
} else if (a[i].a == maxa[a[i].b].first) {
maxa[a[i].b].second++;
}
}
vector<C> all, valid;
for (int i = 0; i < m; i++) {
if (maxa[b[i].e].second != 0) {
all.emplace_back(maxa[b[i].e].first, b[i].c, b[i].d, maxa[b[i].e].second);
}
}
sort(all.begin(), all.end(), [&](const C &x, const C &y) {
return x.a == y.a ? x.c == y.c ? x.d > y.d : x.c > y.c : x.a > y.a;
});
valid.emplace_back(all.front());
for (int i = 1; i < (int)all.size(); i++) {
if (all[i] == valid.back()) {
valid.back().cnt += all[i].cnt;
} else {
valid.emplace_back(all[i]);
}
}
int ans = 0;
fenwick t(fen_size);
for (int i = 0; i < (int)valid.size(); i++) {
if (t.get(valid[i].c, valid[i].d) == 0) {
ans += valid[i].cnt;
}
t.modify(valid[i].c, valid[i].d, 1);
}
cout << "Case #" << ++kase << ": " << ans << endl;
}
return 0;
}

【hdu5517】Triple的更多相关文章

  1. 【BZOJ3771】Triple(生成函数,多项式运算)

    [BZOJ3771]Triple(生成函数,多项式运算) 题面 有\(n\)个价值\(w\)不同的物品 可以任意选择\(1,2,3\)个组合在一起 输出能够组成的所有价值以及方案数. \(n,w< ...

  2. 【BZOJ3771】Triple 生成函数+FFT

    [BZOJ3771]Triple Description 我们讲一个悲伤的故事. 从前有一个贫穷的樵夫在河边砍柴. 这时候河里出现了一个水神,夺过了他的斧头,说: “这把斧头,是不是你的?” 樵夫一看 ...

  3. 【bzoj3771】【xsy1728】Triple

    [bzoj3771][xsy1728] 题意 求\(\sum_{i}[a_i=S]+\sum_{i<j}[a_i+a_j=S]+\sum_{i<j<k}[a_i+a_j+a_k=S] ...

  4. 【BZOJ】【3771】Triple

    生成函数+FFT Orz PoPoQQQ 这个题要算组合的方案,而且范围特别大……所以我们可以利用生成函数来算 生成函数是一个形式幂级数,普通生成函数可以拿来算多重集组合……好吧我承认以上是在瞎扯→_ ...

  5. 【NJU749D】triple(莫比乌斯反演)

    题意: cas<=100 n<=10^5 思路:与两个数的没什么区别 F(d)=(n div d)*(n div d-1)*(n div d-2) div 6 再加上喜闻乐见的下底函数分块 ...

  6. 【BZOJ3771】Triple 生成函数 FFT 容斥原理

    题目大意 有\(n\)把斧头,不同斧头的价值都不同且都是\([0,m]\)的整数.你可以选\(1\)~\(3\)把斧头,总价值为这三把斧头的价值之和.请你对于每种可能的总价值,求出有多少种选择方案. ...

  7. 【bzoj3771】Triple FFT+容斥原理

    题目描述 樵夫的每一把斧头都有一个价值,不同斧头的价值不同.总损失就是丢掉的斧头价值和. 他想对于每个可能的总损失,计算有几种可能的方案. 注意:如果水神拿走了两把斧头a和b,(a,b)和(b,a)视 ...

  8. 【HDOJ5517】Triple(二维BIT)

    题意:给你n个二元组<a,b>, m个三元组<c,d,e>. 如果d = e,那么<a,c,d>会组成一个新的三元组集合G. 问G中有多少个三元组在凸点.(没有其它 ...

  9. 【BZOJ】3771: Triple FTT+生成函数

    [题意]给定n个物品,价值为$a_i$,物品价格互不相同,求选一个或两个或三个的价值为x的方案数,输出所有存在的x和对应方案数.$ai<=40000$. [算法]生成函数+FFT [题解]要求价 ...

随机推荐

  1. Windows冷门快捷键

    Win+Shift+>或者+<光标键,可以使一个程序,在双屏显示器上左右切换. alt+space快捷键相当于在窗口的标题栏上面右键单击,弹出菜单,选择M键,就可以使用光标键上下左右移动来 ...

  2. P1062 数列 题解

    (题目为啥要强调用十进制输出呢,明明就是故意提醒) 分析一下样例 k=3k=3时,数列为:1,3,4,9,10,12,13..1,3,4,9,10,12,13.. 转换成三进制就是:1,10,11,1 ...

  3. python基础学习日记(一)注释(二)算术运算符(三)变量的基本使用

    一.python程序的注释 注释部份程序运行时不起作用.用于说明代码的用途 1.单行注释 # 开始的一行文字,为单行注释 # 单行注释 print("hello python") ...

  4. Mysterious Crime CodeForces - 1043D (哈希)

    大意: 给定m个n排列, 求有多少个公共子串. 枚举每个位置, hash求出最大匹配长度. #include <iostream> #include <sstream> #in ...

  5. nignx简单介绍

    Nginx的产生 没有听过Nginx?那么一定听过它的"同行"Apache吧!Nginx同Apache一样都是一种WEB服务器.基于REST架构风格,以统一资源描述符(Unifor ...

  6. 【opencv源码解析】 二、 cvtColor

    这里以CV_BGR2YUV_I420来讲 1. opencv244 core.cpp void cv::cvtColor( InputArray _src, OutputArray _dst, int ...

  7. PHP之开发环境搭建

    日常开发中,环境的搭建是我们开发的基础,这里介绍几种快速搭建PHP开发环境的方式. 1)lnmp一键安装包[https://lnmp.org] LNMP一键安装包是一个用Linux Shell编写的可 ...

  8. Java是面向对象的编程语言。它不仅吸收了C++语言的优点

    Java是面向对象的编程语言.它不仅吸收了C++语言的优点,而且摒弃了C++中难于理解的多继承和指针的概念.因此,Java语言具有功能强大.使用方便的特点.Java语言作为静态面向对象的编程语言的代表 ...

  9. 微信小程序onLoad、onShow、onHide、onUnload区别

    onLoad:页面第一次加载时触发,从跳转页面返回时不能触发,可以传递参数 onShow:页面显示或从后台跳回小程序时显示此页面时触发,从跳转页面返回时触发,不能传递参数 onHide:页面隐藏,例如 ...

  10. Vue-Cli项目如何查看依赖调用关系?

    Vue是个优秀的前端框架,不管是前端还是后端开发人员都能很快使用Vue来开发应用.但是随着项目开发的深入,组件之间的依赖就变得越来越多,耦合越来越严重.这时候我们迫切地需要分析下组件和依赖之间的调用关 ...