1. 程式人生 > >Luogu3810 三維偏序(陌上花開)

Luogu3810 三維偏序(陌上花開)

【模板】三維偏序(陌上花開)

題目背景

這是一道模板題

可以使用bitset,CDQ分治,K-DTree等方式解決。

題目描述

n 個元素,第i 個元素有aibici三個屬性,設f(i) 表示滿足ajaibjbicjcij 的數量。

對於 d[0,n),求f(i)=d 的數量

輸入輸出格式
輸入格式:

第一行兩個整數nk ,分別表示元素數量和最大屬性值。

之後n行,每行三個整數aibici,分別表示三個屬性值。

輸出格式:

輸出 n行,第d+1行表示f(i)=di 的數量。

輸入輸出樣例
輸入樣例#1:

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

輸出樣例#1:

3
1
3
0
1
0
1
0
0
1

說明

1n100000,1k200000

題解

考慮使用cdq分治,第一維直接排序搞掉,第二維cdq搞成離線,最後一位上資料結構即可。

左半邊對右半邊的貢獻很好統計,左邊為單點加,右邊為區間求和。

程式碼
#include<bits/stdc++.h>
using namespace std; const int M=1e6+5; struct sd{int p,q,r,sum,cot,id;}; bool cmp1(sd a,sd b) { if(a.p!=b.p)return a.p<b.p; if(a.q!=b.q)return a.q<b.q; return a.r<b.r; } bool cmp2(sd a,sd b){return a.q==b.q?(a.r==b.r?a.p<b.p:a.r<b.r):a.q<b.q;} bool operator !=(sd a,sd b){return
a.p!=b.p||a.q!=b.q||a.r!=b.r;} int sum[M],ans[M],n,tot,base=1; sd x[M],que[M]; void in() { int a; scanf("%d%d",&n,&a); while(base<a)base<<=1; for(int i=1;i<=n;++i)scanf("%d%d%d",&x[i].p,&x[i].q,&x[i].r); } void add(int v,int s){v+=base;for(;v;v>>=1)sum[v]+=s;} int query(int le,int ri) { int ans=0;le+=base;ri+=base; for(;le^ri^1;le>>=1,ri>>=1) { if(le&1^1)ans+=sum[le+1]; if(ri&1)ans+=sum[ri-1]; } return ans; } void cdq(int le,int ri) { if(le==ri)return; int mid=(le+ri)>>1; cdq(le,mid);cdq(mid+1,ri); sort(que+le,que+ri+1,cmp2); for(int i=le;i<=ri;++i) { if(que[i].id<=mid)add(que[i].r,que[i].cot); else que[i].sum+=query(0,que[i].r+1); } for(int i=le;i<=ri;++i) if(que[i].id<=mid)add(que[i].r,-que[i].cot); } void ac() { sort(x+1,x+1+n,cmp1); for(int i=1;i<=n;++i) { if(x[i]!=x[i-1])que[++tot]=x[i],que[tot].id=tot; ++que[tot].cot; } cdq(1,tot); for(int i=1;i<=tot;++i)ans[que[i].sum+que[i].cot-1]+=que[i].cot; for(int i=0;i<n;++i)printf("%d\n",ans[i]); } int main() { in();ac(); return 0; }