高维偏序

树套树三维偏序/高维偏序

Posted by TH911 on February 18, 2026

不知道从哪里下的 PDF,感觉写的很好。

处理偏序问题时,如果偏序条件都带等号,则需要考虑两个元素完全相同的情况,这时需要该元素 $a$ 的统计个数 $\textit{cnt}$,然后统计满足偏序条件元素个数 $x$,则 $a$ 的答案为 $x-1$,同时直接做 $\textit{cnt}$ 的贡献。

一维偏序

排序即可。

二维偏序

排序之后树状数组统计即可。

比如逆序对。

三维偏序

luogu P3810 【模板】三维偏序 / 陌上花开

有 $n$ 个元素,第 $ i $ 个元素有 $a_i,b_i,c_i$ 三个属性,设 $ f(i) $ 表示满足 $ a_j \leq a_i$ 且 $ b_j \leq b_i$ 且 $ c_j \leq c_i $ 且 $ j \ne i $ 的 $j$ 的数量。

对于所有 $ d \in [0, n) $,求 $ f(i) = d $ 的数量。

设 $a_i,b_i,c_i$ 最大值为 $k$,$1\leq n\leq10^5,1\leq a_i,b_i,c_i\leq k\leq2\times10^5$。

树套树

考虑先按照 $a$ 排序,之后就是要求满足 $b_j\leq b_i,c_j\leq c_i$,这就是一个二维限制问题。

考虑树套树解决,树状数组套线段树即可。

参考代码

但是需要稍微卡一下空间。

```cpp //#include<bits/stdc++.h> #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace std; constexpr const int N=1e5,V=2e5; struct element{ int a,b,c; }a[N+1]; int n,k,ans[N+1]; int size; struct node{ int l,r; int lChild,rChild; int value; }t[V*80+1]; struct bit{ struct segTree{ int root; int create(node x){ t[++size]=x; return size; } void up(int p){ t[p].value=t[t[p].lChild].value+t[t[p].rChild].value; } void down(int p){ int mid=t[p].l+t[p].r>>1; if(!t[p].lChild){ t[p].lChild=create({t[p].l,mid}); } if(!t[p].rChild){ t[p].rChild=create({mid+1,t[p].r}); } } void add(int p,int x,int k){ if(t[p].l==t[p].r){ t[p].value+=k; return; } int mid=t[p].l+t[p].r>>1; if(x<=mid){ if(!t[p].lChild){ t[p].lChild=create({t[p].l,mid}); } add(t[p].lChild,x,k); }else{ if(!t[p].rChild){ t[p].rChild=create({mid+1,t[p].r}); } add(t[p].rChild,x,k); } up(p); } void add(int x,int k){ add(root,x,k); } int query(int p,int x){ if(t[p].r<=x){ return t[p].value; } // down(p); int ans=0; if(t[p].lChild){ ans=query(t[p].lChild,x); } if(t[p].rChild){ if(t[t[p].rChild].l<=x){ ans+=query(t[p].rChild,x); } } return ans; } int query(int x){ return query(root,x); } }T[V+1]; int lowbit(int x){ return x&-x; } void insert(int b,int c,int x){ while(b<=k){ T[b].add(c,x); b+=lowbit(b); } } int query(int b,int c){ int ans=0; while(b){ ans+=T[b].query(c); b-=lowbit(b); } return ans; } void build(){ for(int i=1;i<=k;i++){ T[i].root=T[i].create({1,k}); } } }T; int main(){ // freopen("test.in","r",stdin); // freopen("test.out","w",stdout); ios::sync_with_stdio(false); cin.tie(0);cout.tie(0); cin>>n>>k; T.build(); for(int i=1;i<=n;i++){ cin>>a[i].a>>a[i].b>>a[i].c; } sort(a+1,a+n+1,[](element a,element b){ if(a.a!=b.a){ return a.a<b.a; }else if(a.b!=b.b){ return a.b<b.b; }else{ return a.c<b.c; } }); for(int i=1;i<=n;i++){ int cnt=1; while(i<n&&a[i+1].a==a[i].a&&a[i+1].b==a[i].b&&a[i+1].c==a[i].c){ i++; cnt++; } T.insert(a[i].b,a[i].c,cnt); ans[T.query(a[i].b,a[i].c)-1]+=cnt; } for(int i=0;i<n;i++){ cout<<ans[i]<<'\n'; } cout.flush(); /*fclose(stdin); fclose(stdout);*/ return 0; } ``` </details>