洛谷P3810 陌上花开 (cdq)

最近才学了cdq,所以用cdq写的代码(这道题也是cdq的模板题)

这道题是个三维偏序问题,先对第一维排序,然后去掉重复的,然后cdq分治即可。

为什么要去掉重复的呢?因为相同的元素互相之间都能贡献,而cdq过程中只能左边贡献右边的,所以要去重。

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 const int N=200005;
 4 struct node{
 5     int a,b,c,cnt,ans;
 6 }s1[N],s2[N];
 7 int n,k,mx,m,top,su[N];
 8 int c[N];//树状数组 
 9  
10 bool cmp1(node x,node y){//按a排序 
11     if(x.a==y.a){
12         if(x.b==y.b) return x.c<y.c;
13         else return x.b<y.b;
14     }
15     else return x.a<y.a;
16 }
17  
18 bool cmp2(node x,node y){//cdq分治过程中对b排序 
19     if(x.b==y.b) return x.c<y.c;
20     else return x.b<y.b;
21 }
22  
23 int lowbit(int x){
24     return x&(-x);
25 }
26  
27 void add(int x,int k){
28     while(x<=mx){
29         c[x]+=k;
30         x+=lowbit(x);
31     }
32 }
33  
34 int query(int x){
35     int sum=0;
36     while(x){
37         sum+=c[x];
38         x-=lowbit(x);
39     }
40     return sum;
41 }
42  
43 void cdq(int l,int r){//cdq 
44     if(l==r) return ;
45     int mid=(l+r)>>1;
46     cdq(l,mid);cdq(mid+1,r);
47     sort(s2+l,s2+1+mid,cmp2);
48     sort(s2+mid+1,s2+r+1,cmp2);
49     int i,j=l;
50     for(int i=mid+1;i<=r;i++){//双指针计算结果 
51         while(s2[i].b>=s2[j].b&&j<=mid){
52             add(s2[j].c,s2[j].cnt);
53             j++;
54         }
55         s2[i].ans+=query(s2[i].c);//计算ans 
56     }
57     for(int i=l;i<j;i++){//清空数组 
58         add(s2[i].c,-s2[i].cnt);
59     }
60 }
61  
62 int main()
63 {
64     scanf("%d%d",&n,&k);
65     mx=k;
66     for(int i=1;i<=n;i++){
67         int a,b,c;
68         scanf("%d%d%d",&a,&b,&c);
69         s1[i].a=a;s1[i].b=b;s1[i].c=c;
70     }
71     sort(s1+1,s1+1+n,cmp1); 
72     for(int i=1;i<=n;i++){//去掉重复的 
73         top++;
74         if(s1[i].a!=s1[i+1].a||s1[i].b!=s1[i+1].b||s1[i].c!=s1[i+1].c){
75             m++;
76             s2[m].a=s1[i].a;s2[m].b=s1[i].b;s2[m].c=s1[i].c;
77             s2[m].cnt=top;
78             top=0;
79         }
80     }
81     cdq(1,m);
82     for(int i=1;i<=m;i++) su[s2[i].ans+s2[i].cnt-1]+=s2[i].cnt;
83     for(int i=0;i<n;i++)
84     cout<<su[i]<<endl; 
85     return 0;
86 }

 

posted @ 2022-04-04 14:36  YHXo  阅读(31)  评论(0编辑  收藏  举报