BZOJ3262:陌上花開 & 洛谷3810:三維偏序——題解


http://www.lydsy.com/JudgeOnline/problem.php?id=3262

https://www.luogu.org/problemnew/show/3810

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

——————————————————————————

CDQ分治不那么裸的題吧……?可能我菜。

(事實證明三維偏序是CDQ最常見的表現形式……我是真的菜)

首先如果我們做過POJ2532的話, 那這題的思路就不難想:我們對一個維度進行排序,對於另一個維度樹狀數組統計比它曉得個數有幾個,那我們就能夠確定它的等級。

不幸的是,這題有三個維度,排掉一個還剩兩個,總不能樹狀數組套樹狀數組吧(我也不會寫啊……)

這時候我們就想到了神奇的CDQ分治(點擊此處獲得原理),但是這並沒有查詢和修改操作啊……

好的我們開始對題目重新理解一下!

首先定義我們的修改操作就是往樹狀數組里添加/刪除節點,我們的查詢操作就是查詢該點的等級。

那么對於一維肯定是要排序的,在那之后我們把根據一維排好的序當做查詢/修改的時間,於是我們就神奇的變成了:先詢問(該點等級),再修改(將節點插入)的在線問題。

那么CDQ就可以上了!我們對每個區間的節點的二維排序之后套樹狀數組查三維即可。

PS1:CDQ具體做法:我們每次添加區間前一半的點,后一半進行查詢(原因不好用語言表達,大致意思為一個點到區間前端的這段區間可以由若干個CDQ區間的整個前半組成)

PS2:本題還有一個坑點,即相同的點也算是比自己丑(……),而樹狀數組對於一串相同的點的查詢,只有最后一個點的答案正確,其他的點的答案分別為:倒數第二與ans差1,倒數第三與ans差2……所以我們預處理一下即可。

#include<cmath>
#include<cstdio>
#include<queue>
#include<cctype>
#include<cstring>
#include<vector>
#include<algorithm>
using namespace std;
typedef long long ll;
const int N=100001;
inline int read(){
    int X=0,w=0; char ch=0;
    while(!isdigit(ch)) {w|=ch=='-';ch=getchar();}
    while(isdigit(ch)) X=(X<<3)+(X<<1)+(ch^48),ch=getchar();
    return w?-X:X;
}
struct flower{
    int x;
    int y;
    int z;
    int num;
    int ans;
}a[N],b[N];
int ans[N],tree[2*N],n,k;
bool cmp(flower a,flower b){
    return (a.x<b.x)||(a.x==b.x&&(a.y<b.y||(a.y==b.y&&a.z<b.z)));
}
bool same(flower a,flower b){
    return (a.x==b.x&&a.y==b.y&&a.z==b.z);
}
inline int lowbit(int t){return t&(-t);}
void add(int x,int y){//將a[x]+y
    for(int i=x;i<=k;i+=lowbit(i))tree[i]+=y;
    return;
}
int query(int x){//1-x區間和
    int res=0;
    for(int i=x;i>0;i-=lowbit(i))res+=tree[i];
    return res;
}
void cdq(int l,int r){
    if(l>=r)return;
    int mid=(l+r)>>1;
    cdq(l,mid);cdq(mid+1,r);
    for(int i=l,j=l,p=mid+1;i<=r;i++){
    if(j<=mid&&(p>r||a[j].y<=a[p].y))b[i]=a[j++];
    else b[i]=a[p++];
    }
    for(int i=l;i<=r;i++){
    a[i]=b[i];
    if(a[i].num<=mid)add(a[i].z,1);
    else a[i].ans+=query(a[i].z);
    }
    for(int i=l;i<=r;i++)if(a[i].num<=mid)add(a[i].z,-1);
    return;
}
int main(){
    n=read();
    k=read();
    for(int i=1;i<=n;i++){
    a[i].x=read();
    a[i].y=read();
    a[i].z=read();
    }
    sort(a+1,a+n+1,cmp);
    flower t;int cnt=1;
    for(int i=n;i>=1;i--){
    if(same(t,a[i])){
        a[i].ans+=cnt;
        cnt++;
    }
    else{
        t=a[i];
        cnt=1;
    }
    }
    for(int i=1;i<=n;i++)a[i].num=i;
    cdq(1,n);
    for(int i=1;i<=n;i++)ans[a[i].ans]++;
    for(int i=0;i<n;i++)printf("%d\n",ans[i]);
    return 0;
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM