zoukankan      html  css  js  c++  java
  • *主席树学习笔记

    未完待续

    主席树

    先来看一个问题:给你一个数列,让你求n次区间第k小值(题目链接

    我们想想:

    第x棵线段树减去第y棵线段树会发生什么?

    第x棵线段树代表的区间是[1,x]

    第y棵线段树代表的区间是[1,y]

    两棵线段树一减

    设x>y,([1,x]−[1,y]=[y+1,x])

    所以这两棵线段树相减可以产生一个新的区间对应的线段树!

    所以,我们只需要建n棵权值线段树(([1,i]))就可以表示出每一个区间了!

    但是又会有一个问题:空间爆了

    我们会发现

    上代码

    #include<bits/stdc++.h>
    #define N 220000
    #define LC t[rt].lc
    #define RC t[rt].rc
    #define _LC t[_rt].lc
    #define _RC t[_rt].rc
    using namespace std;
    int n,m,x,y,k,cnt,size,a[N],b[N],c[N],rt[N];
    struct tree{
    	int sum,lc,rc;
    }t[N<<5];
    void updata(int &rt,int _rt,int l,int r,int k){
    	rt=++cnt;
    	t[rt]=t[_rt];
    	++t[rt].sum;
    	if(l==r)return;
    	int mid=(l+r)>>1;
    	if(k<=mid)updata(LC,_LC,l,mid,k);
    	else updata(RC,_RC,mid+1,r,k);
    }
    int query(int rt,int _rt,int l,int r,int k){
    	if(l==r)return l;
    	int mid=(l+r)>>1,v=t[_LC].sum-t[LC].sum;
    	if(k<=v)return query(LC,_LC,l,mid,k);
    	else return query(RC,_RC,mid+1,r,k-v);
    }
    int main(){
    	scanf("%d%d",&n,&m);
    	for(int i=1;i<=n;i++)scanf("%d",&a[i]),b[i]=a[i];
    	sort(b+1,b+n+1);
    	size=unique(b+1,b+n+1)-b-1;
    	for(int i=1;i<=n;i++)updata(rt[i],rt[i-1],1,size,lower_bound(b+1,b+size+1,a[i])-b);
    	for(int i=1;i<=m;i++){
    		scanf("%d%d%d",&x,&y,&k);
    		printf("%d
    ",b[query(rt[x-1],rt[y],1,size,k)]);
    	}
    }
    

    怎么感觉比普通线段树还短

    参考资料:https://www.cnblogs.com/hanruyun/p/9916299.html
    https://blog.csdn.net/ModestCoder_/article/details/90107874

  • 相关阅读:
    js 复杂研究
    js 页面 保持状态 的方法
    C# 向上取整数
    js 获取dom 为null 测试
    net core 下 接受文件 测试
    layui 源码解读(部分)
    js 定时器
    js addEventListener
    C# 获得对象的命名空间 ?.
    修改maven的默认jdk版本
  • 原文地址:https://www.cnblogs.com/ZTC2019/p/13274444.html
Copyright © 2011-2022 走看看