LUOGU 3810: 陌上花開
——三維偏序
原題傳送門
Description
因爲洛谷題目…好像沒法複製,所以簡單闡述題目大意.
有個元素,第個元素有個屬性,()
設 表示滿足 的 的數量.
求對於,滿足 的 有多少個.
Data
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
.
思路
三維偏序模板題.
n維偏序
三維偏序,屬於一種名爲" 維偏序"的題目.
維偏序形式化地描述如下:
有個元素
其中有個分量
.
不那麼形式化地:
可以參考Description.
就是有一堆元素,每個元素有個屬性.
表示每一個元素都小於等於的屬性的個數.
下方例子僅供參考.
比如有幾個人:(維偏序)
XQQ先生: 算法,編碼都很優秀.(不愧是XQQ),作死能力…(他一向就是那麼優秀)
ZACK先生: 算法優秀,編碼一般,作死能力一般
Mr.F: 算法優秀,編碼…,作死能力一般
本人: 算法一般,編碼一般.,作死能力極強~~(每次都被抓)~~
(作死能力倒序).
那麼可以說:
n維偏序的時間複雜度.
這裏列舉一下各維的時間複雜度
,emm好像似乎大概排序就可以…
,就是求逆序對.…
,這就是我們的重點.事實證明可以是…
三維偏序的暴力做法.
快往這裏看這裏是正解.
暴力做法是十分trival 的.
就像當年做逆序對一樣,的暴力枚舉.
但是這個數據肯定會卡你啊…
所以我們就要優秀優化一波.
這裏有很多種優化方法:
:我不會
:我不會
分治.
由於我很菜各種原因,這裏直接介紹分治.
CDQ分治
CDQ分治,就是用前面的操作更新後面的操作.
並且更好的是它可以不停地套用.
和二分類似,它也將操作區間不斷二分,更新
所以我們可以這樣一波操作.
不斷將詢問二分.
然後按照"左更右"的原則:
- 先將所有元素按 排序.
- 分治後對區間排序,這樣就會保證 有序.
- 如果原來是,那麼就會對後面的產生貢獻.
- 然後還需要判斷.
- 這時候參考逆序對的"二維偏序"就可以了.
所以我們震驚的發現,"三維偏序"可以依靠"二維偏序"實現?
這個規則是否適用於更高維度?
答案是肯定的!
所以我們可以用CDQ套CDQ(套CDQ套CDQ套///).
但是每套一個CDQ就會有一個,所以四維偏序的複雜度(使用CDQ)應該是.
雖然這個還是很優秀,但是好像在之內好像並沒有什麼用.
但是對於三維偏序,這種算法還是綽綽有餘.
Code
#include<bits/stdc++.h>
#define lowbit(x) x&(-x)
using namespace std;
const int N=1e5;
struct node
{
int x,y,z,w,ans;
}a[N],tmp[N];
int c[2*N];
int n,k,cnt;
int ans[N];
void add(int x,int val)
{
for (;x<=k;x+=lowbit(x)) c[x]+=val;
}
int sum(int x)
{
int ans=0;
for (;x>0;x-=lowbit(x)) ans+=c[x];
return ans;
}
bool same(const node a,const node b)
{
return a.x==b.x&&a.y==b.y&&a.z==b.z;
}
bool cmp1(const node &a,const 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;
}
bool cmp2(const node &a,const node &b)
{
if (a.y!=b.y) return a.y<b.y;
if (a.z!=b.z) return a.z<b.z;
return a.x<b.x;
}
void CDQ(int L,int R)
{
if (L==R) return;
int mid=(L+R)>>1;
CDQ(L,mid),CDQ(mid+1,R);
sort(a+L,a+mid+1,cmp2),sort(a+mid+1,a+R+1,cmp2);
int i=mid+1,j=L;
for (;i<=R;i++)
{
while (a[j].y<=a[i].y&&j<=mid) add(a[j].z,a[j].w),j++;
a[i].ans+=sum(a[i].z);
}
for (i=L;i<j;i++) add(a[i].z,-a[i].w);
}
int main()
{
scanf("%d%d",&n,&k);
for (int i=1;i<=n;i++) scanf("%d%d%d",&tmp[i].x,&tmp[i].y,&tmp[i].z);
sort(tmp+1,tmp+n+1,cmp1);
int p=0,c=0;
for (int i=1;i<=n;i++)
{
c++;
if (!same(tmp[i],tmp[i+1])) a[++p]=tmp[i],a[p].w=c,c=0;
}
int rn=n;
n=p;
CDQ(1,n);
for (int i=1;i<=n;i++)
ans[a[i].ans+a[i].w-1]+=a[i].w;
for (int i=0;i<rn;i++) printf("%d\n",ans[i]);
return 0;
}
感謝奆老關注 qwq ?
順便悼念一下我那逝去的博文…