bzoj3262: 陌上花开(CDQ+树状数组处理三维偏序问题)

题目链接:https://www.lydsy.com/JudgeOnline/problem.php?id=3262

题目大意:中文题目

具体思路:CDQ可以处理的问题,一共有三维空间,对于第一维我们直接按照从小到大排序就可以了,然后就开始处理第二维,第二维的话我们通过cdq来维护,然后第三维通过树状数组维护就可以了。

刚开始做CDQ的问题,个人觉得CDQ处理的就是把一整个大的问题转换成多个子问题进行求解,然后很重要的一个的地方就是解决前面一个子问题对后面的问题的影响。

AC代码:

 1 #include<iostream>
 2 #include<stack>
 3 #include<stdio.h>
 4 #include<cmath>
 5 #include<algorithm>
 6 using namespace std;
 7 # define ll long long
 8 # define inf 0x3f3f3f3f
 9 const int maxn = 2e5+100;
10 struct node{
11 int x,y,z;
12 int ans,cnt;
13 }q[maxn];
14 int maxstate;
15 bool cmp1(node t1,node t2){
16 if(t1.x!=t2.x)return t1.x<t2.x;
17 if(t1.y!=t2.y)return t1.y<t2.y;
18 return t1.z<t2.z;
19 }
20 bool cmp2(node t1,node t2){
21 if(t1.y!=t2.y)return t1.y<t2.y;
22 return t1.z<t2.z;
23 }//注意两个cmp的不同,对于第一个cmp我们只是初始的状态,但是对于第二个cmp,我们处理的是x已经排好的前提下了,如果这个时候再对q进行排序的话,会打乱y的正常顺序。
24 int vis[maxn],tree[maxn<<2];
25 int lowbit(int x){return x&(-x);}
26 void update(int x,int val){
27 while(x<=maxstate){
28 tree[x]+=val;
29 x+=lowbit(x);
30 }
31 }
32 int  ask(int x){
33 int ans=0;
34 while(x){
35 ans+=tree[x];
36 x-=lowbit(x);
37 }
38 return ans;
39 }
40 void cdq(int l,int r){
41 if(l==r){
42 q[l].ans+=q[l].cnt-1;
43 return ;
44 }
45 int mid=(l+r)>>1;
46 cdq(l,mid);
47 cdq(mid+1,r);
48 sort(q+l,q+mid+1,cmp2);
49 sort(q+mid+1,q+r+1,cmp2);
50 int tmp=l;
51 for(int i=mid+1;i<=r;i++){
52 while(tmp<=mid&&q[i].y>=q[tmp].y){
53 update(q[tmp].z,q[tmp].cnt),tmp++;
54 }
55 q[i].ans+=ask(q[i].z);
56 }
57 for(int i=l;i<tmp;i++){
58 update(q[i].z,-q[i].cnt);
59 }//消除前面一个子问题对后面的子问题的影响
60 }
61 int main(){
62     //freopen("hqx.in","r",stdin);
63 int n;
64 scanf("%d %d",&n,&maxstate);
65 for(int i=1;i<=n;i++){
66 scanf("%d %d %d",&q[i].x,&q[i].y,&q[i].z);
67 q[i].cnt=1;
68 q[i].ans=0;
69 }
70 int tot=0;
71 sort(q+1,q+n+1,cmp1);
72 for(int i=1;i<=n;i++){
73 if(i!=1&&q[i].x==q[tot].x&&q[i].y==q[tot].y&&q[i].z==q[tot].z)q[tot].cnt++;
74 else q[++tot]=q[i];
75 }
76 cdq(1,tot);
77 for(int i=1;i<=tot;i++){
78 vis[q[i].ans]+=q[i].cnt;
79 }
80 for(int i=0;i<n;i++){
81 printf("%d\n",vis[i]);
82 }
83 return 0;
84 }

 

转载于:https://www.cnblogs.com/letlifestop/p/10456288.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值