HDU - 5126 stars (CDQ分治)

题目大意:一共有Q(1<=Q<=50000)组操作,操作分为两种:

1.在x,y,z处添加一颗星星

2.询问以(x1,y1,z1)与(x2,y2,z2)为左上和右下顶点的矩形之间的星星数

所有坐标取值范围均为[1,1e9]

思路:由于坐标取值范围太大(即使离散化后也很大),3维的数组肯定开不下,所以只能另辟蹊径。

解法一(两重CDQ+树状数组,需将z坐标离散化):

1)将每个查询操作拆分为8个(容斥),将所有操作放入一个数组qr中

2)将所有操作按时间排序(其实不用,因为读入的顺序就是按时间排好的)

3)第一次分治:将qr中每个子区间按x坐标从小到大排序,将左区间元素与右区间查询放入qr2中

4)第二次分治(嵌套在第一次分治中):将qr2中每个子区间按y坐标从小到大排序,统计左区间元素对右区间查询的贡献(利用树状数组记录z值)

注意每次分治结束后,需将左右区间的所有元素按相应坐标大小归并排好序。另外离散化的时候注意下标要从1开始而不是从0开始,否则树状数组可能会陷入死循环(在这个地方T了n次...QAQ)

 1 #include<bits/stdc++.h>
 2
 3 using namespace std;
 4 const int N=5e5+10;
 5 struct QR {
 6     int f,x,y,z,i;
 7 } qr[N],qr2[N],qr3[N];
 8 int c[N],n,ans[N],nq,tot,zz[N],maxz;
 9 int lowbit(int x) {return x&-x;}
10 void add(int u,int x) {
11     for(; u<=maxz; u+=lowbit(u))c[u]+=x;
12 }
13 int get(int u) {
14     int ret=0;
15     for(; u; u-=lowbit(u))ret+=c[u];
16     return ret;
17 }
18
19 void cdq2(int l,int r) {
20     if(l==r)return;
21     int mid=(l+r)>>1;
22     cdq2(l,mid),cdq2(mid+1,r);
23     int L=l,R=mid+1;
24     for(; R<=r; ++R)if(qr2[R].f) {
25             for(; L<=mid&&qr2[L].y<=qr2[R].y; ++L)if(!qr2[L].f)add(qr2[L].z,1);
26             ans[qr2[R].i]+=get(qr2[R].z)*qr2[R].f;
27         }
28     for(int i=l; i<L; ++i)if(!qr2[i].f)add(qr2[i].z,-1);
29     L=l,R=mid+1;
30     for(int i=l; i<=r; ++i) {
31         if(R>r||(L<=mid&&qr2[L].y<=qr2[R].y))qr3[i]=qr2[L++];
32         else qr3[i]=qr2[R++];
33     }
34     for(int i=l; i<=r; ++i)qr2[i]=qr3[i];
35 }
36
37 void cdq1(int l,int r) {
38     if(l==r)return;
39     int mid=(l+r)>>1;
40     cdq1(l,mid),cdq1(mid+1,r);
41     int L=l,R=mid+1,m=0;
42     for(; R<=r; ++R)if(qr[R].f) {
43             for(; L<=mid&&qr[L].x<=qr[R].x; ++L)if(!qr[L].f)qr2[m++]=qr[L];
44             qr2[m++]=qr[R];
45         }
46     if(m>0)cdq2(0,m-1);
47     L=l,R=mid+1;
48     for(int i=l; i<=r; ++i) {
49         if(R>r||(L<=mid&&qr[L].x<qr[R].x))qr2[i]=qr[L++];
50         else qr2[i]=qr[R++];
51     }
52     for(int i=l; i<=r; ++i)qr[i]=qr2[i];
53 }
54
55 int main() {
56     int T;
57     scanf("%d",&T);
58     while(T--) {
59         nq=tot=0;
60         memset(c,0,sizeof c);
61         memset(ans,0,sizeof ans);
62         scanf("%d",&n);
63         for(int i=0; i<n; ++i) {
64             int f;
65             scanf("%d",&f);
66             if(f==1) {
67                 int x,y,z;
68                 scanf("%d%d%d",&x,&y,&z);
69                 qr[nq++]= {0,x,y,z,0};
70             } else {
71                 int x1,y1,z1,x2,y2,z2;
72                 scanf("%d%d%d%d%d%d",&x1,&y1,&z1,&x2,&y2,&z2);
73                 qr[nq++]= {1,x2,y2,z2,tot};
74                 qr[nq++]= {-1,x1-1,y2,z2,tot};
75                 qr[nq++]= {-1,x2,y1-1,z2,tot};
76                 qr[nq++]= {-1,x2,y2,z1-1,tot};
77                 qr[nq++]= {1,x1-1,y1-1,z2,tot};
78                 qr[nq++]= {1,x2,y1-1,z1-1,tot};
79                 qr[nq++]= {1,x1-1,y2,z1-1,tot};
80                 qr[nq++]= {-1,x1-1,y1-1,z1-1,tot++};
81             }
82         }
83         maxz=0;
84         for(int i=0; i<nq; ++i)zz[maxz++]=qr[i].z;
85         sort(zz,zz+maxz);
86         maxz=unique(zz,zz+maxz)-zz;
87         for(int i=0; i<nq; ++i)qr[i].z=lower_bound(zz,zz+maxz,qr[i].z)-zz+1;
88         cdq1(0,nq-1);
89         for(int i=0; i<tot; ++i)printf("%d\n",ans[i]);
90     }
91     return 0;
92 }

解法二(三重CDQ,无需离散化):

1)2)3)同解法一,第四步将q2中每个子区间按z坐标从小到大排序,将左区间元素与右区间查询放入qr3中,然后利用类似归并排序求逆序对的方法对qr3中的贡献进行统计

 1 #include<bits/stdc++.h>
 2
 3 using namespace std;
 4 const int N=5e5+10;
 5 struct QR {
 6     int f,x,y,z,i;
 7 } qr[N],qr2[N],qr3[N],qr4[N];
 8 int n,ans[N],nq,tot;
 9
10 void cdq3(int l,int r) {
11     if(l==r)return;
12     int mid=(l+r)>>1;
13     cdq3(l,mid),cdq3(mid+1,r);
14     int L=l,R=mid+1,m=0;
15     for(; R<=r; ++R)if(qr3[R].f) {
16             for(; L<=mid&&qr3[L].z<=qr3[R].z; ++L)if(!qr3[L].f)m++;
17             ans[qr3[R].i]+=m*qr3[R].f;
18         }
19     L=l,R=mid+1;
20     for(int i=l; i<=r; ++i) {
21         if(R>r||(L<=mid&&qr3[L].z<=qr3[R].z))qr4[i]=qr3[L++];
22         else qr4[i]=qr3[R++];
23     }
24     for(int i=l; i<=r; ++i)qr3[i]=qr4[i];
25 }
26
27
28 void cdq2(int l,int r) {
29     if(l==r)return;
30     int mid=(l+r)>>1;
31     cdq2(l,mid),cdq2(mid+1,r);
32     int L=l,R=mid+1,m=0;
33     for(; R<=r; ++R)if(qr2[R].f) {
34             for(; L<=mid&&qr2[L].y<=qr2[R].y; ++L)if(!qr2[L].f)qr3[m++]=qr2[L];
35             qr3[m++]=qr2[R];
36         }
37     if(m>0)cdq3(0,m-1);
38     L=l,R=mid+1;
39     for(int i=l; i<=r; ++i) {
40         if(R>r||(L<=mid&&qr2[L].y<=qr2[R].y))qr3[i]=qr2[L++];
41         else qr3[i]=qr2[R++];
42     }
43     for(int i=l; i<=r; ++i)qr2[i]=qr3[i];
44 }
45
46 void cdq1(int l,int r) {
47     if(l==r)return;
48     int mid=(l+r)>>1;
49     cdq1(l,mid),cdq1(mid+1,r);
50     int L=l,R=mid+1,m=0;
51     for(; R<=r; ++R)if(qr[R].f) {
52             for(; L<=mid&&qr[L].x<=qr[R].x; ++L)if(!qr[L].f)qr2[m++]=qr[L];
53             qr2[m++]=qr[R];
54         }
55     if(m>0)cdq2(0,m-1);
56     L=l,R=mid+1;
57     for(int i=l; i<=r; ++i) {
58         if(R>r||(L<=mid&&qr[L].x<qr[R].x))qr2[i]=qr[L++];
59         else qr2[i]=qr[R++];
60     }
61     for(int i=l; i<=r; ++i)qr[i]=qr2[i];
62 }
63
64 int main() {
65     int T;
66     scanf("%d",&T);
67     while(T--) {
68         nq=tot=0;
69         memset(ans,0,sizeof ans);
70         scanf("%d",&n);
71         for(int i=0; i<n; ++i) {
72             int f;
73             scanf("%d",&f);
74             if(f==1) {
75                 int x,y,z;
76                 scanf("%d%d%d",&x,&y,&z);
77                 qr[nq++]= {0,x,y,z,0};
78             } else {
79                 int x1,y1,z1,x2,y2,z2;
80                 scanf("%d%d%d%d%d%d",&x1,&y1,&z1,&x2,&y2,&z2);
81                 qr[nq++]= {1,x2,y2,z2,tot};
82                 qr[nq++]= {-1,x1-1,y2,z2,tot};
83                 qr[nq++]= {-1,x2,y1-1,z2,tot};
84                 qr[nq++]= {-1,x2,y2,z1-1,tot};
85                 qr[nq++]= {1,x1-1,y1-1,z2,tot};
86                 qr[nq++]= {1,x2,y1-1,z1-1,tot};
87                 qr[nq++]= {1,x1-1,y2,z1-1,tot};
88                 qr[nq++]= {-1,x1-1,y1-1,z1-1,tot++};
89             }
90         }
91         cdq1(0,nq-1);
92         for(int i=0; i<tot; ++i)printf("%d\n",ans[i]);
93     }
94     return 0;
95 }

两种解法复杂度均为O(nlog3n),但解法二比解法一常数大很多,这道题可以勉强A掉,而同样思路的BZOJ3262用同样的方法就会被卡掉。

原文地址:https://www.cnblogs.com/asdfsag/p/10269495.html

时间: 2024-10-06 14:22:43

HDU - 5126 stars (CDQ分治)的相关文章

HDU 5126 stars cdq分治+树状数组

题目链接:点击打开链接 题意: T个case n个操作 1. (x,y,z) 在三维平面的点上增加1 2.询问区间范围内的权值和. 思路: cdq分治套cdq分治,然后套树状数组即可.. #include <stdio.h> #include <iostream> #include <algorithm> #include <sstream> #include <stdlib.h> #include <string.h> #inclu

hdu 4366 Successor - CDQ分治 - 线段树 - 树分块

Sean owns a company and he is the BOSS.The other Staff has one Superior.every staff has a loyalty and ability.Some times Sean will fire one staff.Then one of the fired man’s Subordinates will replace him whose ability is higher than him and has the h

Boring Class HDU - 5324 (CDQ分治)

Mr. Zstu and Mr. Hdu are taking a boring class , Mr. Zstu comes up with a problem to kill time, Mr. Hdu thinks it’s too easy, he solved it very quickly, what about you guys? Here is the problem: Give you two sequences L1,L2,...,Ln and R1,R2,...,Rn. Y

hdu 1541 (cdq分治)

Problem Description Astronomers often examine star maps where stars are represented by points on a plane and each star has Cartesian coordinates. Let the level of a star be an amount of the stars that are not higher and not to the right of the given

HDU Shell Necklace CDQ分治+FFT

Shell Necklace Problem Description Perhaps the sea‘s definition of a shell is the pearl. However, in my view, a shell necklace with n beautiful shells contains the most sincere feeling for my best lover Arrietty, but even that is not enough. Suppose

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 解法:将操作编号也加入到

HDU 5618:Jam&#39;s problem again(CDQ分治+树状数组处理三维偏序)

http://acm.hdu.edu.cn/showproblem.php?pid=5618 题意:-- 思路:和NEUOJ那题一样的.重新写了遍理解了一下,算作处理三维偏序的模板了. 1 #include <cstdio> 2 #include <algorithm> 3 #include <iostream> 4 #include <cstring> 5 using namespace std; 6 #define INF 0x3f3f3f3f 7 #d

HDU 3507 Print Article(CDQ分治+分治DP)

[题目链接] http://acm.hdu.edu.cn/showproblem.php?pid=3507 [题目大意] 将长度为n的数列分段,最小化每段和的平方和. [题解] 根据题目很容易得到dp[j]=min(dp[k]+(s[j]-s[k])2),因为是从前往后转移,且决策单调,因此在CDQ分治的同时进行分治DP即可. [代码] #include <cstdio> typedef long long LL; const int N=500005; int n,M,t; LL f[N],

HDU 5730 Shell Necklace(CDQ分治+FFT)

[题目链接] http://acm.hdu.edu.cn/showproblem.php?pid=5730 [题目大意] 给出一个数组w,表示不同长度的字段的权值,比如w[3]=5表示如果字段长度为3,则其权值为5,现在有长度为n的字段,求通过不同拆分得到的字段权值乘积和. [题解] 记DP[i]表示长度为i时候的答案,DP[i]=sum_{j=0}^{i-1}DP[j]w[i-j],发现是一个卷积的式子,因此运算过程可以用FFT优化,但是由于在计算过程中DP[j]是未知值,顺次计算复杂度是O(