【洛谷P3810 三维偏序】

题目描述:

  有 n 个元素,第 i 个元素有 ai​,bi,ci 三个属性,设 f(i,j) 表示满足 ajai 且 bjbi 且 cjci 的 j 的数量。

  对于 d[0,n),求 f(i) = d 的数量。

输入格式:

  第一行两个整数n,k分别表示元素数量和最大属性值。

  之后 n 行,每行三个整数 aibici,分别表示三个属性值。

输出格式:

  输出 nn 行,第 d + 1d+1 行表示 f(i) = df(i)=d 的 ii 的数量。

输入样例:

 10 3
 3 3 3
 2 3 3
 2 3 1
 3 1 1
 3 1 2
 1 3 1
 1 1 2
 1 2 2
 1 3 2
 1 2 1

输出样例:

 3
 1
 3
 0
 1
 0
 1
 0
 0
 1

题解:

  cdq分治。(感觉细节多多)

  我先说说如何理解cdq分治吧。(这东西可以省去树套树的一棵树)假装这时你左右两边都处理好了,开始合并。比如这题,如果左边的y<=右边的y,说明这个点对我右边当前询问有影响,所以先去bit维护添加z,那么当右边询问左边有多少个点满足时,bit维护添加的y都是小于当前y且全部添加,那么直接询问z这个值域的值即可。

  如果问右边关于右边的答案有没有统计,就是归并的问题了。(归并过程顺便把y排序了,方便上面合并)

  每个区间的bit是一次性的,所以要清空。(如果不清会重复计算)

 1 #include<iostream>
 2 #include<cstdlib>
 3 #include<cstring>
 4 #include<cstdio>
 5 #include<algorithm>
 6 using namespace std;
 7 struct node{
 8     int x,y,z,num,sum;
 9 }    a[100005],t[100005],tt[100005];
10 int cnt,ans[10000005];
11 inline bool cmp(node X,node Y){
12     if(X.x!=Y.x)    return X.x<Y.x;
13     if(X.y!=Y.y)    return X.y<Y.y;
14     return X.z<Y.z;
15 }
16 int n,K,bit[10000005];
17 inline void add(int x,int k){
18     for(int i=x;i<=K;i+=(i&-i)){
19         bit[i]+=k;
20     }
21 }
22 inline int query(int x){
23     int ret=0;
24     for(int i=x;i;i-=(i&-i)){
25         ret+=bit[i];
26     }
27     return ret;
28 }
29 inline void clean(int x){
30     for(int i=x;i<=K;i+=(i&-i)){
31         bit[i]=0;
32     }
33 }
34 inline void merge(int l,int r){
35     int pos=0;
36     if(l==r)    return;
37     int mid=(l+r)>>1;
38     merge(l,mid);merge(mid+1,r);
39     int L=l,R=mid+1;
40     while(R<=r){
41         while(L<=mid && (t[L].y<t[R].y || (t[L].y==t[R].y && t[L].z<=t[R].z))){
42             tt[++pos]=t[L];
43             add(tt[pos].z,tt[pos].num);L++;
44         }
45         tt[++pos]=t[R];
46         tt[pos].sum+=query(tt[pos].z);
47         R++;
48     }
49     for(int i=L;i<=mid;i++){
50         tt[++pos]=t[i];
51     }
52     pos=0;
53     for(int i=l;i<=r;i++){
54         t[i]=tt[++pos];
55         clean(tt[pos].z);
56     }
57 }
58 int main(){
59     scanf("%d%d",&n,&K);
60     for(int i=1;i<=n;i++){
61         scanf("%d%d%d",&a[i].x,&a[i].y,&a[i].z);
62     }
63     sort(a+1,a+n+1,cmp);
64     for(int i=1;i<=n;i++){
65         if(a[i].x==a[i-1].x && a[i].y==a[i-1].y && a[i].z==a[i-1].z){
66             t[cnt].num++;
67         }
68         else    t[++cnt]=a[i],t[cnt].num++;
69     }
70     merge(1,cnt);
71     for(int i=1;i<=cnt;i++){
72         ans[t[i].num+t[i].sum-1]+=t[i].num;
73     }
74     for(int i=0;i<n;i++){
75         printf("%d\n",ans[i]);
76     }
77     return 0;
78 }
posted @ 2017-11-28 22:09  LittleOrange  阅读(438)  评论(0编辑  收藏  举报