主席树,喵~
Posted RDCのACM奇幻之旅
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了主席树,喵~相关的知识,希望对你有一定的参考价值。
稍微总结一下主席树吧
Too Difficult!搞了一天搞出一大堆怎么令人悲伤的辣鸡代码。总之先总结一下吧,以后碰到这种问题直接拿去毒害队友好了。
Lv.1 最基本的操作
区间k大值
区间内有多少个数字小于等于x
query 操作了解一下
int query(int new_k,int old_k,int l,int r,int x) { // cnt <= x
if(x<l) return 0; // 这个地方比较喜。小心点。
if(l==r) return sum[new_k]-sum[old_k];
int mid=(l+r)>>1;
if(mid<x) return sum[lson[new_k]]-sum[lson[old_k]]+query(rson[new_k],rson[old_k],mid+1,r,x);
else return query(lson[new_k],lson[old_k],l,mid,x);
}
目前对主席树很naive的理解:主席树相当于对每一个前缀都维护一个线段树,然后发现相邻两棵线段树长得好像哎!然后就是资源重复利用了。
既然是维护每一个前缀,所以,我们不仅能拿主席树来施展线性结构,还能施展树状结构!比如说我们可以查询树上两点间路径点权的k小值。
Lv.2 树上路径上点权k小值
栗子:SPOJ-COT
线性结构上
iterval(l,r)=T(r)-T(l-1)
树状结构上
path(u,v) = T(u)+T(v)-T(lca)-T(Parent of lca)
Lv.2 矩形内有多少个点
给出很多个点。Q组询问,每组询问查询一个矩形内有几个点。
按横坐标排序,把纵坐标放到主席树上,然后就相当于区间内有多少个数字小于等于x啦!
把细节考虑好!还是很友好的。
#include <iostream>
#include <algorithm>
using namespace std;
const int N=6000000+10;
#define f(x) (1LL*x*(x-1)/2)
typedef long long LL;
int lson[N],rson[N],sum[N],root[N],pid;
int n,q,p[N];
void build(int &k,int l,int r){
k=++pid;
if(l==r) return;
int mid=(l+r)>>1;
build(lson[k],l,mid);
build(rson[k],mid+1,r);
}
void change(int old,int &k,int l,int r,int pos,int x) {
k=++pid;
lson[k]=lson[old],rson[k]=rson[old],sum[k]=sum[old]+x;
if(l==r) return;
int mid=(l+r)>>1;
if(pos<=mid) change(lson[k],lson[k],l,mid,pos,x);
else change(rson[k],rson[k],mid+1,r,pos,x);
}
int query(int new_k,int old_k,int l,int r,int x) { // cnt <= x
if(x<l) return 0;
if(l==r) return sum[new_k]-sum[old_k];
int mid=(l+r)>>1;
if(mid<x) return sum[lson[new_k]]-sum[lson[old_k]]+query(rson[new_k],rson[old_k],mid+1,r,x);
else return query(lson[new_k],lson[old_k],l,mid,x);
}
int count(int x1,int x2,int y1,int y2) { //
if(x1>x2||y1>y2) return 0;
int cnt1 = query(root[x2],root[x1-1],1,n,y1-1);
int cnt2 = query(root[x2],root[x1-1],1,n,y2);
return cnt2-cnt1;
}
int main(){
scanf("%d%d",&n,&q);
for(int i=1;i<=n;i++) {
scanf("%d",&p[i]);
}
build(root[0],1,n);
for(int i=1;i<=n;i++) {
change(root[i-1],root[i],1,n,p[i],1);
}
for(int i=1;i<=q;i++){
int l,d,r,u;
scanf("%d%d%d%d",&l,&d,&r,&u);
int LU = count(1,l-1,u+1,n);
int LD = count(1,l-1,1,d-1);
int RU = count(r+1,n,u+1,n);
int RD = count(r+1,n,1,d-1);
int L = l-1; int U = n-u;
int R = n-r; int D = d-1;
LL A = f(L)+f(R)+f(U)+f(D);
LL B = f(LU)+f(LD)+f(RU)+f(RD);
LL ret = 1LL*n*(n-1)/2-(A-B);
printf("%lld\n", ret);
}
}
以上,于4/28,mark一下。
之后,待补的坑:
- BIT套主席树
- 主席树的区间更新
学数据结构是不可能学数据结构的,这辈子都不可能学数据结构!
以上是关于主席树,喵~的主要内容,如果未能解决你的问题,请参考以下文章