http://www.lydsy.com/JudgeOnline/problem.php?id=3262
https://www.luogu.org/problemnew/show/3810
Description
Input
Output
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; }