【题解】P3810 【模板】三维偏序(陌上花开)- $CDQ$ - 三维偏序
P3810 【模板】三维偏序(陌上花开)
声明:本博客所有题解都参照了网络资料或其他博客,仅为博主想加深理解而写,如有疑问欢迎与博主讨论✧。٩(ˊᗜˋ)و✧*。
题目描述
有 \(n\) 个元素,第 \(i\) 个元素有 \(a_i,b_i,c_i\) 三个属性,设 \(f(i)\) 表示满足 \(a_j \leq a_i\) 且 \(b_j \leq b_i\) 且 \(c_j \leq c_i\) 且 \(j \ne i\) 的 \(j\) 的数量。
对于 \(d \in [0, n)\),求 \(f(i) = d\) 的数量。
\(\\\)
\(\\\)
\(Solution\)
这道题和树状数组那道一样
这里的 \(a\) 可以看做树状数组里的时间,只不过那里的操作是有序的,所以这道题第一步是把 \(a\) 排个序,当做 \(CDQ\) 的时间
然后 \(b\) 和那道题的位置一样,于是也可以归并排序balabala
但是还有一个 \(c\) ,我们可以用一个树状数组维护,累计答案就可!
完结
然而这道题有非常多的坑点...
\(1.\)对于相等的三元组,要把它们合并,并且要存它们的数量,在树状数组累计的时候加的应该是那个三元组的数量,最后统计答案,每个三元组还得加上数量 \(-1\) ,因为相等也算答案(关于为什么树状数组不用判相等,因为每个操作的时间是唯一的,所以不可能有相等的)
\(2.\)排序的时候如果 \(a\) 不相等则按 \(a\) 的大小排,如果 \(a\) 相等再按 \(b\) 的大小排,还相等再按 \(c\) 的大小排,不然计算答案会出错
\(3.\)由于每次都要清空树状数组,虽然照理来说是跑满 \(O(n\log{n})\) ,\(10^7\) 可以过来着,但是被卡了...重新开一个数组记录被修改过的树状数组,清空就快一些
完结撒花✿✿ヽ(°▽°)ノ✿
\(\\\)
\(\\\)
\(Code\)
#include<bits/stdc++.h>
#define mid ((l + r) >> 1)
#define lowbit(x) x & -x
#define F(i, x, y) for(int i = x; i <= y; ++ i)
using namespace std;
int read();
const int N = 1e5 + 5;
const int M = 2e5 + 5;
int n, k, m, cnt;
int tree[M], f[N], d[N], s[N], vis[M];
struct node{
int a, b, c, num, w;
}p[N], tmp[N];
bool cmp(node x, node y)
{
if(x.a != y.a) return x.a < y.a;
if(x.b != y.b) return x.b < y.b;
return x.c < y.c;
}
void add(int pos, int v){for(; pos <= m; pos += lowbit(pos)) {tree[pos] += v; if(! vis[pos]) s[++ s[0]] = pos, vis[pos] = 1;}}
int getans(int pos){int res = 0; for(; pos; pos -= lowbit(pos)) res += tree[pos]; return res;}
void CDQ(int l, int r)
{
if(l == r) return;
CDQ(l, mid), CDQ(mid + 1, r);
int i = l, j = mid + 1, o = l - 1;
while(i <= mid && j <= r)
if(p[i].b < p[j].b || p[i].b == p[j].b && p[i].c <= p[j].c)
add(p[i].c, p[i].w), tmp[++ o] = p[i ++];
else f[p[j].num] += getans(p[j].c), tmp[++ o] = p[j ++];
while(i <= mid) tmp[++ o] = p[i ++];
while(j <= r) f[p[j].num] += getans(p[j].c), tmp[++ o] = p[j ++];
F(i, 1, s[0]) tree[s[i]] = 0, vis[s[i]] = 0; s[0] = 0;
F(i, l, r) p[i] = tmp[i];
}
int main()
{
n = read(), m = read();
F(i, 1, n) p[i].a = read(), p[i].b = read(), p[i].c = read();
sort(p + 1, p + 1 + n, cmp);
F(i, 1, n)
{
++ k;
if(p[i].a != p[i + 1].a || p[i].b != p[i + 1].b || p[i].c != p[i + 1].c)
tmp[++ cnt] = p[i], tmp[cnt].num = cnt, tmp[cnt].w = k, k = 0;
}
F(i, 1, cnt) p[i] = tmp[i];
CDQ(1, cnt);
F(i, 1, cnt) d[f[p[i].num] + p[i].w - 1] += p[i].w;
F(i, 0, n - 1) printf("%d\n", d[i]);
return 0;
}
int read()
{
int x = 0;
char c = getchar();
while(c < '0' || c > '9') c = getchar();
while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
return x;
}