BZOJ 3262 陌上花开 (三维偏序CDQ+树状数组)

题目大意:

题面传送门 

三维偏序裸题

首先,把三元组关于$a_{i}$排序

然后开始$CDQ$分治,回溯后按$b_{i}$排序

现在要处理左侧对右侧的影响了,显然现在左侧三元组的$a_{i}$都小于等于右侧

而$c_{i}$这一维需要用权值树状数组维护

归并排序时,已知左侧右侧两个指针分别是$i,j$

如果$b_{i} \leq bj$,将左侧已经遍历过的三元组的$c_{i}$推入树状数组,然后$i++$

如果$b_{i}>bj$,那么右侧能取到的贡献就是树状数组内$\leq c_{j}$的三元组数量,然后$j++$

 

可三元组有重复的啊!

如果我们不去重,假设有两个相同的三元组,靠前的三元组会得不到后面的贡献

还需要去重,并额外记录相同三元组数量

 

这道题的判定条件三个元是小于等于

发现我们只关于$a_{i}$排序也不行啊

在归并过程中会发现有一些$b_{i}$或者是$c_{i}$明明比较大,却得不到后面较小的贡献

这是由于小于等于的情况也合法,而我们必须让较大的在后面,才能保证后面能取到前面的贡献

所以排序过程中第二维还要按$b_{i}$排序,第三维按$c_{i}$

 

 1 #include <vector>
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <algorithm>
 5 #define N1 100100
 6 #define ll long long
 7 #define dd double
 8 #define inf 0x3f3f3f3f3f3f3f3fll
 9 using namespace std;
10 
11 int gint()
12 {
13     int ret=0,fh=1;char c=getchar();
14     while(c<'0'||c>'9'){if(c=='-')fh=-1;c=getchar();}
15     while(c>='0'&&c<='9'){ret=ret*10+c-'0';c=getchar();}
16     return ret*fh;
17 }
18 int n,nn,K;
19 struct node{
20 int id,num,a,b,c;
21 friend bool operator == (const node &s1,const node &s2)
22 {return (s1.a==s2.a)&&(s1.b==s2.b)&&(s1.c==s2.c);}
23 friend bool operator < (const node &s1,const node &s2)
24 {
25     if(s1.a!=s2.a) return s1.a<s2.a;
26     if(s1.b!=s2.b) return s1.b<s2.b;
27     return s1.c<s2.c;
28 }
29 }p[N1],t[N1],tmp[N1];
30 
31 struct b_{i}T{
32 int s[N1<<1];
33 void update(int x,int w){for(int i=x;i<=K;i+=(i&(-i))) s[i]+=w;}
34 int query(int x){int ans=0; for(int i=x;i>0;i-=(i&(-i))) ans+=s[i]; return ans;}
35 }b;
36 int f[N1],hs[N1],que[N1],tl;
37 void CDQ(int L,int R)
38 {
39     if(R-L<=1) return;
40     int M=(L+R)>>1;
41     CDQ(L,M); CDQ(M,R);
42     int i=L,j=M,cnt=0;
43     while(i<M&&j<R)
44     {
45         if(t[i].b<=t[j].b){
46             b.update(t[i].c,t[i].num); 
47             tmp[++cnt]=t[i]; i++; que[++tl]=cnt;
48         }else{
49             f[t[j].id]+=b.query(t[j].c);
50             tmp[++cnt]=t[j]; j++;
51         }
52     }
53     while(i<M){tmp[++cnt]=t[i]; i++;}
54     while(j<R){f[t[j].id]+=b.query(t[j].c); tmp[++cnt]=t[j]; j++;}
55     while(tl) i=que[tl--],b.update(tmp[i].c,-tmp[i].num);
56     for(i=L;i<R;i++) t[i]=tmp[i-L+1];
57 }
58 
59 int main()
60 {
61     scanf("%d%d",&n,&K);
62     int i;
63     for(i=1;i<=n;i++) p[i].a=gint(),p[i].b=gint(),p[i].c=gint();
64     sort(p+1,p+n+1); 
65     for(i=1;i<=n;i++) 
66         if(!(p[i]==p[i-1])) t[++nn]=p[i],t[nn].num=1;
67         else t[nn].num++;
68     for(i=1;i<=nn;i++) t[i].id=i;
69     CDQ(1,nn+1);
70     for(i=1;i<=nn;i++) hs[f[t[i].id]+t[i].num-1]+=t[i].num;
71     for(i=0;i<n;i++) printf("%d\n",hs[i]);
72     return 0;
73 }

 

posted @ 2018-12-31 19:41  guapisolo  阅读(181)  评论(0编辑  收藏  举报