學習筆記 多維偏序

2022-02-06 02:38:25 字數 2984 閱讀 2707

一般情況下,我們比較乙個數大小,就是ai>aj即可,

而在上公升子串行中,當i>j並且ai>aj的時候,才可以認為i這位的數大於j這位的數。

這就是乙個二維偏序。

類似的,有n個數,每個數m個屬性,乙個數比另乙個數大,當且僅當這個數的所有屬性都大於另乙個數。

這就是乙個m維偏序。

對於三維偏序,可以用cdq分治、排序、樹狀陣列處理。

有 n 個元素,第 i 個元素有 ai​、bi​、ci​三個屬性,設 f(i)表示滿足 aj​≤ai​且bj​≤bi​且cj​≤ci​的 j的數量。

對於d∈[0,n) ,求 f(i) = d的數量

三維偏序的模板題。

我們先按照a從小到大排序,

然後cdq分治。

先遞迴到兩邊,

回溯到這一層之後,把左兒子的所有的數按照b排序,右兒子的所有數也按照b排序。

這樣,左兒子的數之間雖然a不一定遞增,但是因為開始按照a排序,所以左邊所有的數的a一定都小於右邊的數。

b排好序之後,

兩個指標j,i分別從1~mid,mid+1~r 即左右兒子區間的起止點開始走,,

對於右邊的乙個數i,當j的數的b值不大於i的b值時,不斷向後走j,並且把這些數的c值放進乙個權值樹狀陣列裡,

當j的b值大於i之後,當前所有左兒子裡面,b小於i這個數的數的c屬性都放進樹狀陣列裡了。

只有放進去的這些數才可能來更新f值。

在i向後走之前,f[a[i].ans]+=query(a[i].z),滿足第三個條件的數也找到了。

就把所有當前這個層裡面,符合條件的數都找出來了。

最後,把樹狀陣列加上的 1都消去。

由於cdq分治,會把i之前的所有的數都分成logn個區間,更新完f[i]了。

大家可以手動畫圖,或者模擬一下。

複雜度:nlogn^2

那麼,這個演算法是怎麼樣實現三維偏序的處理呢?

1.對於a,開始直接排序,並且,每次是先遞迴左右兒子,再處理這一層,

所以保證乙個數pi前面的所有的數,不論之後怎麼換位置,都不會到i的後面。

這就利用位置保證了所有可能更新f[i]的數對於a都是合法的。

2.對於b,我們每次回溯的時候,按照b排了乙個序,

對於左子區間對右子區間的影響,通過指標,把b小於等於i的數的所有數的c放進了樹狀陣列裡。

這樣,i前面的logn個區間,會把所有b小於i的b的數都考慮一遍的。也合法。

3.對於c,直接通過樹狀陣列字首和,一步就求出來了當前合法的所有數了。

相當於乙個篩,留下a合法的,留下b合法的,最後能被c留下的,就是所有合法的了。

注意因為是小於等於號,所以我們先把所有的完全相同的數合併成乙個數,統計的時候,乙個數也大於等於自己。再加上就好了。

就是細節問題。

#includeusing

namespace

std;

const

int n=100000+10

;int

n,m;

intf[n];

struct

nodea[n],b[n];

intpp;

bool

cmpx(node p,node q)

return p.x

}bool

cmpy(node p,node q)

return p.y

}struct

ta

int ask(int

x)}t;

void cdq(int l,int

r) a[i].ans+=t.ask(a[i].z);

}for(i=l;i)

}int

ans[n];

intmain()

sort(b+1,b+m+1

,cmpx);

int c=0

;

for(int i=1;i<=m;i++)

}cdq(

1,n);

for(int i=1;i<=n;i++)

for(int i=0;i)

return0;

}

三維偏序

要是維數再多了呢??

給出n個人的5個科目分數,給出q個詢問~~,每次給你5個科目的具體分數。求一共有多少個人對應的5個科目都小於等於你的科目分數~~

n,q<=50000

這就是5維偏序了。

顯然cdq分治不容易解決了。難以巧妙處理5維。

就考慮比較暴力的思路:

把成績5種分成5組,每一組從小到大按成績排序。

每次二分出id,id的成績恰好位於成績查詢邊界。

這樣可以知道該成績是有幾個人不滿足。

但是,由於有5個,所以必須知道都是誰。。。。

用乙個bitset<50001>s[5][50000]表示,第i維,前j個人滿足不合格的情況下,都是誰(s[i][j][k]=1表示,i維,編號是k的人,成績比倒數第j名可能還差。)

然後預處理出bitset(每次j加一,就把j+1的人或進去就行了),查詢的時候,二分id,之後取出這5個bitset,&一下就知道最後剩誰了,統計1的個數。

但是bitset還是太大了,不是mle,就是tle。

所以,考慮分塊!??!

bitset<50001>s[5][250]表示,第i維,前j塊不合格,都是誰

預處理比較容易,乙個塊乙個塊內暴力處理,最後從前到後相鄰的塊乙個字首或就可以了

查詢的時候,

二分出來乙個id,在塊k裡,

就找到k,把k-1塊的不合格人都找出來,之後剩下的暴力加進去就可以啦

複雜度:o(5 * q * sqrtn)(不算預處理)

因為這個是n<=50000,所以分塊卡不掉。

這種資料範圍,多維偏序都可以類似擴充套件開來。

本質上還是乙個篩。不過用了bitset和分塊優化。

總結:感覺多維偏序在生活中還是比較常見的,

比方說,你期末考試之後,想看看完虐多少個人?(每一科都比ta高)

就是多維偏序了。

bitset做多維偏序

很久以前就聽說這個大名鼎鼎的東西 暴力 了,現在才去寫。其實很簡單,對每一維排序,從左到右掃,維護乙個bitset表示這位之前的某個點是否出現 即出現則該位為1否則0 查詢某個數時則在每一維的排序完陣列二分找到最右邊 這個數這一維權值的位置,取出該位的bitset,將每一維的bitset與起來即可得...

等價,偏序和全序

等價 設 r 是某個集合 a 上的乙個二元關係。若 r 滿足以下條件 自反性 對稱性 傳遞性 則稱 r 是乙個定義在 a 上的等價關係。習慣上會把等價關係的符號由 r 改寫為 例如,設 上的關係r 如下 其中 與 y模 3 同餘,即 x 除以 3 的餘數與 y 除以 3 的餘數相等。例子有 1r4,...

貪心 偏序 treap

貪心 偏序 treap c.booking system 題意 乙個餐館,n批顧客,每批顧客都想要坐在同一張桌子上,人數為c,將付的錢是p,m張桌子,有容量desk c,得到最多的錢,輸出兩兩配對結果 題解 貪心,有兩種貪心策略 1.讓桌子選,根據容量從小到大依次選,選可以滿足要人數求中錢最多的 2...