Luogu3810 三維偏序(陌上花開)
阿新 • • 發佈:2019-01-01
【模板】三維偏序(陌上花開)
題目背景
這是一道模板題
可以使用bitset,CDQ分治,K-DTree等方式解決。
題目描述
有 個元素,第 個元素有、 、三個屬性,設 表示滿足且 且 的 的數量。
對於 ,求 的數量
輸入輸出格式
輸入格式:
第一行兩個整數 、 ,分別表示元素數量和最大屬性值。
之後行,每行三個整數 、 、,分別表示三個屬性值。
輸出格式:
輸出 行,第行表示 的 的數量。
輸入輸出樣例
輸入樣例#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
說明
題解
考慮使用分治,第一維直接排序搞掉,第二維搞成離線,最後一位上資料結構即可。
左半邊對右半邊的貢獻很好統計,左邊為單點加,右邊為區間求和。
程式碼
#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;
}