题目描述: 有 n 个元素,每个元素都有三个属性
a
i
,
b
i
,
c
i
a_i,b_i,c_i
ai,bi,ci。对于每个
j
j
j ,求
a
i
<
=
a
j
a_i<=a_j
ai<=aj 且
b
i
<
=
b
j
b_i<=b_j
bi<=bj 且
c
i
<
=
c
j
c_i<=c_j
ci<=cj 的
i
i
i 的个数。
1
<
=
n
,
a
i
,
b
i
,
c
i
<
=
2
e
5
1<=n,a_i,b_i,c_i<=2e5
1<=n,ai,bi,ci<=2e5。数据保证不会有
a
,
b
,
c
a,b,c
a,b,c 均相等的元素。
问题分析: 类似二维的树状数组求逆序对。对于三维而言,先对
a
a
a 排序,再用线段树套 treap 查区间
[
1
,
b
j
]
[1,b_j]
[1,bj] 中,
c
<
=
c
j
c<=c_j
c<=cj 的个数。后者可以用线段树套 treap 做。
思路: 思路与线段树维护区间
[
l
,
r
]
[l,r]
[l,r] 一样 ,对于每个区间
[
l
,
r
]
[l,r]
[l,r] ,其就有对应一个
t
r
e
a
p
treap
treap 维护区间
[
l
,
r
]
[l,r]
[l,r] 之间的所有点。空间复杂度:
n
l
o
g
n
nlogn
nlogn
#include<bits/stdc++.h>usingnamespace std;constint N=1e7+10;int root[N],cnt,ans[N],R=2e5;structnode{int val,key,l,r,size;} tr[N];voidpushup(int now){
tr[now].size=tr[tr[now].l].size+tr[tr[now].r].size+1;}intnewnode(int val){
tr[++cnt].val=val;
tr[cnt].l=tr[cnt].r=0;
tr[cnt].size=1;
tr[cnt].key=rand();return cnt;}voidsplit(int now,int&a,int&b,int val){if(now==0){
a=b=0;return;}if(tr[now].val<=val)a=now,split(tr[now].r,tr[a].r,b,val);else b=now,split(tr[now].l,a,tr[b].l,val);pushup(now);}voidmerge(int&now,int a,int b){//把已 a 为根的树和已 b 为根的树合并为以 now 为根的树if(a==0||b==0){
now=a+b;return;}if(tr[a].key>tr[b].key)now=a,merge(tr[now].r,tr[a].r,b);else now=b,merge(tr[now].l,a,tr[b].l);pushup(now);}voidinsert(int&root,int val){//在root这棵树内插入一个值为val的元素 int x=0,y=0;split(root,x,y,val-1);merge(x,x,newnode(val));merge(root,x,y);}intlowbit(int x){return x&(-x);}voidupdate(int x,int val){for(int i=x;i<=R;i+=lowbit(i))insert(root[i],val);}intquery(int x){int ans=0;for(int i=x;i>0;i-=lowbit(i))ans+=findAns(root[i]);return ans;}
例题1:三维逆序对数量
题目描述: 有 n 个元素,每个元素都有三个属性
a
i
,
b
i
,
c
i
a_i,b_i,c_i
ai,bi,ci。对于每个
j
j
j ,求
a
i
<
=
a
j
a_i<=a_j
ai<=aj 且
b
i
<
=
b
j
b_i<=b_j
bi<=bj 且
c
i
<
=
c
j
c_i<=c_j
ci<=cj 的
i
i
i 的个数。
1
<
=
n
,
a
i
,
b
i
,
c
i
<
=
2
e
5
1<=n,a_i,b_i,c_i<=2e5
1<=n,ai,bi,ci<=2e5。数据保证不会有
a
,
b
,
c
a,b,c
a,b,c 均相等的元素。
问题分析: 类似二维的树状数组求逆序对。对于三维而言,先对
a
a
a 排序,再用线段树套 treap 查区间
[
1
,
b
j
]
[1,b_j]
[1,bj] 中,
c
<
=
c
j
c<=c_j
c<=cj 的个数。后者可以用线段树套 treap 做。