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

传送门


真是一道毒瘤题(弄了接近一下午+一晚上)

解题思路

先对所有的点按照a-b-c的优先值从小到大排序,然后去重(注意要记录每一个有几个重复的,因为条件是小于等于,所以重复的对答案也有影响),然后再按照关键字b归并排序,排序过程中,用树状数组记录c值,每一次合并时如果是右半部分的b值较小,答案就加上先前的所有c值小于这个c值的个数。

由于用memset时间复杂度过大,所以进行完操作后用for循环对所有更改过的点进行修改。

然后因为答案问的不是总数,所以用一系列数组来维护各种值,及其恶心。

然后注意k值实际上就是树状数组的边界,千万不能用n,否则会wa三个点。

然后才能顺利AC。

AC代码

 1 #include<iostream>
 2 #include<algorithm>
 3 #include<cmath>
 4 #include<cstdio>
 5 #include<cstring>
 6 using namespace std;
 7 const int maxn=100005;
 8 int n,k,ans[maxn],anss[maxn],numm[maxn];
 9 struct node{
10     int id,a,b,c,num;
11 }p[maxn],q[maxn];
12 bool cmp(const node &x,const node &y){
13     if(x.a!=y.a){
14         return x.a<y.a;
15     }
16     if(x.b!=y.b){
17         return x.b<y.b;
18     }
19     return x.c<y.c;
20 }
21 inline int lowbit(int x){
22     return x&-x;
23 }
24 int c[2*maxn];
25 void update(int x,int v){
26     for(int i=x;i<=k;i+=lowbit(i)){
27         c[i]+=v;
28     }
29 }
30 int query(int x){
31     int res=0;
32     for(int i=x;i>0;i-=lowbit(i)){
33         res+=c[i];
34     }
35     return res;
36 }
37 void divide(int l,int r){
38     if(l==r) return;
39     int mid=(l+r)>>1;
40     int p1=l,p2=mid+1,tot=0;
41     divide(l,mid);
42     divide(mid+1,r);
43     while(p1<=mid||p2<=r){
44         if(p1<=mid&&(p2>r||p[p1].b<=p[p2].b)){
45             q[++tot]=p[p1++];
46             update(q[tot].c,q[tot].num);
47         }else{
48             q[++tot]=p[p2++];
49             ans[q[tot].id]+=query(q[tot].c);
50         }
51     }
52     for(int i=l;i<=mid;i++){
53         update(p[i].c,-p[i].num);
54     }
55     for(int i=1;i<=tot;i++){
56         p[l+i-1]=q[i];
57     }
58 }
59 int main()
60 {
61     cin>>n>>k;
62     for(int i=1;i<=n;i++){
63         scanf("%d%d%d",&p[i].a,&p[i].b,&p[i].c);
64     }
65     sort(p+1,p+n+1,cmp);
66     int tot=0;
67     for(int i=1;i<=n;){
68         int j=i,cnt=0;
69         while(j<=n&&p[i].a==p[j].a&&p[i].b==p[j].b&&p[i].c==p[j].c){
70             p[i].num++;
71             cnt++;
72             j++;
73         }
74         q[++tot]=p[i];
75         numm[tot]=cnt;
76         i=j;
77     }
78     int nn=n;
79     n=tot;
80     memset(p,0,sizeof(p));
81     for(int i=1;i<=tot;i++) p[i]=q[i],p[i].id=i;
82     divide(1,n);
83     for(int i=1;i<=n;i++){
84         ans[i]+=numm[i]-1;
85     }
86     for(int i=1;i<=n;i++){
87         anss[ans[i]]+=numm[i];
88     }
89     for(int i=0;i<nn;i++) printf("%d\n",anss[i]);
90     return 0;
91 }

 寒假作业已经放弃了qwq

posted @ 2020-02-15 22:49  尹昱钦  阅读(131)  评论(1编辑  收藏  举报