洛谷 P3810 【模板】三维偏序(陌上花开) (cdq分治模板)

在solve(L,R)中,需要先分治solve两个子区间,再计算左边区间修改对右边区间询问的贡献。

注意,计算额外的贡献时,两子区间各自内部的顺序变得不再重要(不管怎么样左边区间的都发生在右边之前),于是就少了一维



https://www.lydsy.com/JudgeOnline/problem.php?id=3262

https://www.luogu.org/problemnew/show/P3810

此题每个操作既是修改又是查询

对于此题,先按一维排序,在solve(L,R)中先solve两个子区间,然后把L到R的操作按二维排序(由于cdq分治类似归并的特性此时两个子区间内部二维都是有序的,可以直接二路归并),然后就是一个对二、三维求逆序对的过程(只不过只有归并前在第一个区间内的修改生效,归并前在第二个区间内的查询要更新答案)

可以记一下每个元素在按第一维排序后的编号(以下代码中q[i].num),来判断它归并前是哪个区间里的

注意:此题第一维相同的实际并不存在顺序关系,理应同时处理然后同时计算贡献,但排序后它们间总是要存在一个特定顺序的,所以要加一些奇怪的特判

具体的话:首先一开始排序的时候三个关键字都要依次考虑(而不是只考虑第一维),这样可以保证排序后大部分情况下后面的不会对前面产生贡献

上面还漏考虑了完全相等的三元组,如果它们存在则后面也会对前面产生贡献。因此只要在开始solve前补上这些后面对前面产生的贡献即可

归并可以简化为

merge(q+lp,q+mid+1,q+mid+1,q+rp+1,tmp+lp);
copy(tmp+lp,tmp+rp+1,q+lp);

inplace_merge(q+lp,q+mid+1,q+rp+1);
 1 #include<cstdio>
 2 #include<algorithm>
 3 using namespace std;
 4 struct Q
 5 {
 6     int a,b,c,ans,num;
 7 }q[100100],tmp[100100];
 8 int n,k;
 9 bool c1(const Q &a,const Q &b)    {return a.a<b.a||(a.a==b.a&&a.b<b.b)||(a.a==b.a&&a.b==b.b&&a.c<b.c);}
10 bool operator<(const Q &a,const Q &b)    {return a.b<b.b||(a.b==b.b&&a.num<b.num);}
11 bool operator==(const Q &a,const Q &b)    {return a.a==b.a&&a.b==b.b&&a.c==b.c;}
12 int dat[200100];
13 const int N=200000;
14 #define lowbit(x) ((x)&(-x))
15 void addx(int pos,int d)
16 {
17     for(;pos<=N;pos+=lowbit(pos))    dat[pos]+=d;
18 }
19 int sum(int pos)
20 {
21     int ans=0;
22     for(;pos>0;pos-=lowbit(pos))    ans+=dat[pos];
23     return ans;
24 }
25 int num[100100];
26 void solve(int lp,int rp)
27 {
28     if(lp==rp)    return;
29     int mid=lp+(rp-lp)/2;
30     solve(lp,mid);solve(mid+1,rp);
31     int k=lp-1,i,j;
32     for(i=lp,j=mid+1;i<=mid&&j<=rp;)
33     {
34         ++k;
35         if(q[i]<q[j])    tmp[k]=q[i++];
36         else    tmp[k]=q[j++];
37     }
38     while(i<=mid)    tmp[++k]=q[i++];
39     while(j<=rp)    tmp[++k]=q[j++];
40     for(i=lp;i<=rp;i++)    q[i]=tmp[i];
41     for(i=lp;i<=rp;i++)
42     {
43         if(q[i].num<=mid)    addx(q[i].c,1);
44         else    q[i].ans+=sum(q[i].c);
45     }
46     for(i=lp;i<=rp;i++)
47         if(q[i].num<=mid)
48             addx(q[i].c,-1);
49 }
50 int main()
51 {
52     int i,j,t,tt=0;
53     scanf("%d%d",&n,&t);
54     for(i=1;i<=n;i++)    scanf("%d%d%d",&q[i].a,&q[i].b,&q[i].c);
55     sort(q+1,q+n+1,c1);
56     for(i=1;i<=n;i++)
57     {
58         tt++;
59         if(i==n||!(q[i]==q[i+1]))
60         {
61             for(j=i-tt+1,t=tt-1;j<=i;j++)    q[j].ans+=t,--t;
62             tt=0;
63         }
64     }
65     for(i=1;i<=n;i++)    q[i].num=i;
66     solve(1,n);
67     for(i=1;i<=n;i++)    num[q[i].ans]++;
68     for(i=0;i<n;i++)    printf("%d\n",num[i]);
69     return 0;
70 }

原文地址:https://www.cnblogs.com/hehe54321/p/9028492.html

时间: 2024-11-06 03:29:49

洛谷 P3810 【模板】三维偏序(陌上花开) (cdq分治模板)的相关文章

三维偏序:CDQ分治

cdq分治是一种常用的降维手段,可以解决偏序问题. 题目 给定$n$个三元组$(x, y, z)$,给定一个$f(a)$,表示所有元素$b$(自己不算),它的$x,y,z$均小于等于$a$的对应$x,y,z$,求$[0, n)$中每种$f$值的个数. $n \leq 100000$ $x, y, z \leq 200000$ 简单模型 一维:仅有$x$:按$x$排序即可. 二维:有$(x, y)$,按先$x$后$y$顺序排序,然后将$y$值用树状数组统计. 三维偏序:cdq分治解法 思想:类似归

BZOJ3262:陌上花开 &amp; 洛谷3810:三维偏序——题解

两者题一样,方便没有bzoj权限的朋友. http://www.lydsy.com/JudgeOnline/problem.php?id=3262 https://www.luogu.org/problemnew/show/3810 Description 有n朵花,每朵花有三个属性:花形(s).颜色(c).气味(m),又三个整数表示.现要对每朵花评级,一朵花的级别是它拥有的美丽能超过的花的数量.定义一朵花A比另一朵花B要美丽,当且仅当Sa>=Sb,Ca>=Cb,Ma>=Mb.显然,两朵

BZOJ3262/洛谷P3810 陌上花开 CDQ分治 三维偏序 树状数组

原文链接http://www.cnblogs.com/zhouzhendong/p/8672131.html 题目传送门 - BZOJ3262 题目传送门 - 落谷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$的数量.对于$d\in [0,n)$,求$f(i)=d$的数量. $n\leq 100000,max\{a_i,b_i,c_i|i

【洛谷P3810 三维偏序】

题目描述: 有 n 个元素,第 i 个元素有 ai?,bi,ci? 三个属性,设 f(i,j) 表示满足 aj?≤ai? 且 bj?≤bi? 且 cj?≤ci? 的 j 的数量. 对于 d∈[0,n),求 f(i) = d 的数量. 输入格式: 第一行两个整数n,k分别表示元素数量和最大属性值. 之后 n 行,每行三个整数 ai?.bi?.ci?,分别表示三个属性值. 输出格式: 输出 nn 行,第 d + 1d+1 行表示 f(i) = df(i)=d 的 ii 的数量. 输入样例: 10 3

BZOJ 3262: 陌上花开 [CDQ分治 三维偏序]

Description 有n朵花,每朵花有三个属性:花形(s).颜色(c).气味(m),又三个整数表示.现要对每朵花评级,一朵花的级别是它拥有的美丽能超过的花的数量.定义一朵花A比另一朵花B要美丽,当且仅当Sa>=Sb,Ca>=Cb,Ma>=Mb.显然,两朵花可能有同样的属性.需要统计出评出每个等级的花的数量. Input 第一行为N,K (1 <= N <= 100,000, 1 <= K <= 200,000 ), 分别表示花的数量和最大属性值. 以下N行,每

HDU 5126(stars)四维偏序,cdq分治

题意:给两种操作,进行5万次.操作一:加入一个三维序偶(a,b,c)到集合S里:第二种操作,给两个三维序偶(a1,b1,c1)和(a2,b2,c2),问当前S里有多少个序偶(a,b,c)满足a1<=a<=a2, b1<=b<=b2, c1<=c<=c2.题目保证了a1<=a2,b1<=b2,c1<=c2.所有数在[1,1e9]内 链接:http://acm.hdu.edu.cn/showproblem.php?pid=5126 解法:将操作编号也加入到

luogu3810 陌上花开 (cdq分治)

求三维偏序 设三维为a,b,c.先对a排序,这样i的偏序就只能<i. 然而排序的时候需要三个维度都判断一遍,最后还要去重,不然会出现实际应该记答案的数出现在它后面的情况. (排序用的函数里不要写类似于<=之类的东西啊..会出奇奇怪怪的问题的(RE)) 然后分治来做,我们在做区间[l,r]的时候,先去做[l,m]和[m+1,r] 之后左区间[l,m],右区间[m+1,r]都已经按照b排好序了,而且左右两区间内部的答案已经统计过了,所以现在只要考虑左区间中满足(右区间的数)的数量就好了. 那么就也

BZOJ3262陌上花开 CDQ分治_BIT+Treap

三个属性, 第一个属性用cdq分治处理, 以第一个属性为关键字从小到大排序, 那么考虑一朵花的等级, 只需考虑排在其前面的花的其他属性(特殊情况是有相同的花,根据题意,对一段相同的花,以排在最后的一朵花的答案为准), 第二三维可以用树状数组加Treap解决, 以每朵花第二属性数值作为位置(因为最大属性k < 2e5, 可以不用离散化, 直接用属性的数值对应树状数组中的下标), 树状数组的每个节点建一颗Treap, 这颗Treap里存的是相应区间里的花的第三个属性, 询问时类似于树状数组求前缀和,

HDU4742----Pinball Game 3D(三维LIS、CDQ分治)

题意:三维空间内 n个小球,对应坐标(x,y,z).输出LIS的长度以及方案数. 首先可以先按x排序,先降低一维,然后 剩下y .z,在y上进行CDQ分治,按y的大小用前面的更新后面的.z方向离散化之后用树状数组维护就可以了. 1 #include <set> 2 #include <map> 3 #include <cmath> 4 #include <ctime> 5 #include <queue> 6 #include <stack