分类
标签
2-SAT AC自动机 BFS CDQ dfs DP fail树 FFT FFT&NTT FWT hash KD-Tree KMP LCA SPFA STL Tarjan Treap Trie 主席树 乱搞 二分 二分图匹配 二分答案 二维SPFA 交互 位运算 其他 最小生成树 分块 区间DP 半平面交 博弈论 可持久化 可持久化Trie树 后缀数组 图库 平衡树 并查集 插头DP 数学 数论 无旋Treap 日记 暴力 权值树状数组 栈 树DP 树套树 树状数组 树贪心 概率DP 模拟 欧拉定理 点分治 状压DP 生成函数 矩阵乘 线性规划 线段树 组合 网络流 群论 莫比乌斯反演 计算几何 贪心 费用流 高斯消元
831 字
4 分钟
BZOJ 3262 陌上花开 CDQ
题目描述
有n朵花,每朵花有三个属性:花形(s)、颜色(c)、气味(m),又三个整数表示。现要对每朵花评级,一朵花的级别是它拥有的美丽能超过的花的数量。定义一朵花A比另一朵花B要美丽,当且仅当Sa>=Sb,Ca>=Cb,Ma>=Mb。显然,两朵花可能有同样的属性。需要统计出评出每个等级的花的数量。
输入格式
第一行为N,K (1 <= N <= 100,000, 1 <= K <= 200,000), 分别表示花的数量和最大属性值。 以下N行,每行三个整数si, ci, mi (1 <= si, ci, mi <= K),表示第i朵花的属性
输出格式
包含N行,分别表示评级为0…N-1的每级花的数量。
样例输入
10 3
3 3 3
2 3 3
2 3 1
3 1 1
3 1 2
1 3 1
1 1 2
1 2 2
1 3 2
1 2 1
样例输出
3
1
3
0
1
0
1
0
0
1
提示
1 <= N <= 100,000, 1 <= K <= 200,000
题解
三维偏序
将一个维度作为时间。
比如我令 颜色(c) 为时间维。
那么第一步将除时间(颜色)以外的一个维度排序,
比如说我这里将 花形(s) 排序
那么我们要保证这一维(花形) 时刻有序。
然后我们分治时间(颜色);
我选择的方法是暴力sort
, 先递归。
那么在分治后左边的花型一定是小于右边的。
所以只要将左右分别按时间排序, 对于每一个右边的值, 将左边时间比他小的更新到树状数组中。 然后查询第三维小于他的个数就可以更新答案了。
一些具体的细节可以看代码实现
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
const int N = 100005;
const int M = 200005;
struct data
{
int s, c, m, pos, num, ans;
bool operator < (const data &a) const
{
if (s == a.s && c == a.c) return m < a.m;
if (s == a.s) return c < a.c;
return s < a.s;
}
}a[N], b[N];
const bool cmp(const data &a, const data &b)
{
if (a.c == b.c) a.m < b.m;
return a.c < b.c;
}
int Sum[M], cnt, Color[M], C;
#define lowbit(_) ((_) & (-_))
void add(int x, int c)
{
for (int i = x; i <= M; i += lowbit(i))
{
if (Color[i] != C) Sum[i] = 0;
Color[i] = C;
Sum[i] += c;
}
}
int Query(int x)
{
int ans = 0;
for (int i = x; i > 0; i -= lowbit(i))
{
if (Color[i] == C)
ans += Sum[i];
}
return ans;
}
void CDQ(int l, int r)
{
if (l == r) return;
int mid = l + r >> 1;
CDQ(l, mid), CDQ(mid + 1, r);
sort(b + l, b + mid + 1, cmp);
sort(b + mid + 1, b + r + 1, cmp);
C++;
for (int j = mid + 1, i = l; j <= r; j++)
{
for (; b[i].c <= b[j].c && i <= mid; i++)
add(b[i].m, b[i].num);
b[j].ans += Query(b[j].m);
}
}
int main()
{
int n, k;
scanf ("%d%d", &n, &k);
for (int i = 1; i <= n; i++){
scanf ("%d%d%d", &a[i].s, &a[i].c, &a[i].m);
a[i].pos = i;
}
sort(a + 1, a + n + 1);
for (int i = 1; i <= n; i++)
{
if (a[i].c == a[i - 1].c && a[i].s == a[i - 1].s && a[i].m == a[i - 1].m)
b[cnt].num++;
else
b[++cnt] = a[i], b[cnt].num = 1;
}
// for (int i = 1; i <= cnt; i++) printf ("%d%c", b[i].pos, " \n"[i == cnt]);
CDQ(1, cnt);
// for (int i = 1; i <= cnt; i++) printf ("%d%c", b[i].ans, " \n"[i == cnt]);
// while(1);
static int Ans[N];
for (int i = 1; i <= cnt; i++) Ans[b[i].ans + b[i].num - 1] += b[i].num;
for (int i = 0; i < n; i++) printf ("%d\n", Ans[i]);
// while (1);
}