洛谷題目鏈接https://www.luogu.org/problem/P3810
BZOJ題目鏈接https://www.lydsy.com/JudgeOnline/problem.php?id=3262
Description
有n朵花,每朵花有三個屬性:花形(s)、顏色(c)、氣味(m),用三個整數表示。
現在要對每朵花評級,一朵花的級別是它擁有的美麗能超過的花的數量。
定義一朵花A比另一朵花B要美麗,當且僅Sa>=Sb,Ca>=Cb,Ma>=Mb。
顯然,兩朵花可能有同樣的屬性。需要統計出評出每個等級的花的數量。
Input
第一行爲N,K (1 <= N <= 100,000, 1 <= K <= 200,000 ), 分別表示花的數量和最大屬性值。
以下N行,每行三個整數si, ci, mi (1 <= si, ci, mi <= K),表示第i朵花的屬性
Output
包含N行,分別表示評級爲0...N-1的每級花的數量。
Sample Input
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
Sample Output
3
1
3
0
1
0
1
0
0
1
。。。蜜汁BUG,重構之後才過了QAQ
三維偏序比二維偏序多了一維,但我們還是可以按照二維偏序的思路來想。先固定住第一維,然後對於第二維用歸併排序,第三維用樹狀數組。
我們在歸併的時候考慮 [l,mid] 對 [mid+1,r] 的貢獻。因爲我們已經按屬性 a 排過序了,所以在排序屬性 b 的時候,無論屬性 a 怎麼被打亂,[mid+1,r] 所有元素的屬性 a 一定不小於 [l,mid] 中所有元素的屬性 a,那麼我們就可以把[l,mid]內的屬性z一個個放到樹狀數組裏面統計了,和二維偏序是一樣的做法。接下來還有一個比較重要的就是重複元素--由於這並不是真真的座標,所以他們會重和,所以我們需要對重複的元素進行剔除和累加。
以下是AC代碼:
#include <bits/stdc++.h>
using namespace std;
const int mac=1e5+10;
const int maxn=2e5+10;
int n,m;
int ans[mac],c[maxn];
struct node
{
int x,y,z,ans,f;
}a[mac],b[mac];
bool cmp(node a,node b)
{
if (a.x!=b.x) return a.x<b.x;
if (a.y!=b.y) return a.y<b.y;
return a.z<b.z;
}
int lowbit(int x)
{
return x&-x;
}
void update(int pos,int val)
{
while (pos<=m){
c[pos]+=val;
pos+=lowbit(pos);
}
}
int query(int pos)
{
int sum=0;
while (pos>0){
sum+=c[pos];
pos-=lowbit(pos);
}
return sum;
}
void cdq(int l,int r)
{
if (l==r) return;
int mid=(l+r)>>1;
cdq(l,mid);cdq(mid+1,r);
int ll=l,rr=mid+1,cnt=l-1;
while (ll<=mid && rr<=r){
if (a[ll].y<=a[rr].y){//這個時候後半段對前半段是不會產生貢獻的,所以不用統計前半段的答案
update(a[ll].z,a[ll].f);
b[++cnt]=a[ll++];
}
else {
a[rr].ans+=query(a[rr].z);
b[++cnt]=a[rr++];
}
}
while (ll<=mid){
update(a[ll].z,a[ll].f);//實際上這裏的這個是沒有用的,只不過是爲了方便之後的清空
b[++cnt]=a[ll++];
}
while (rr<=r){
a[rr].ans+=query(a[rr].z);
b[++cnt]=a[rr++];
}
for (int i=l; i<=mid; i++) update(a[i].z,-a[i].f);
cnt=0;
for (int i=l; i<=r; i++) a[i]=b[i];
}
int main()
{
scanf ("%d%d",&n,&m);
for (int i=1; i<=n; i++){
scanf ("%d%d%d",&a[i].x,&a[i].y,&a[i].z);
a[i].f=1;
}
sort(a+1,a+1+n,cmp);
int cnt=1;
for (int i=2; i<=n; i++){
if (a[i].x==a[cnt].x && a[i].y==a[cnt].y && a[i].z==a[cnt].z)
a[cnt].f++;//f保留的是重複元素的個數
else a[++cnt]=a[i];
}
cdq(1,cnt);
for (int i=1; i<=cnt; i++){
ans[a[i].ans+a[i].f-1]+=a[i].f;//由於=是成立的,所以我們要加上相等的個數
}
for (int i=0; i<n; i++)
printf ("%d\n",ans[i]);
return 0;
}