• 权值线段树


    权值线段树

    定义

    在一些计数问题中,线段树用于维护值域(一段权值范围),这样的线段树也称为权值线段树

    排序与离散化

    因为$sum$数组的下标是$x_{max}$,所以如果不做离散化的话,空间会出问题。

    void Init() {
    	std::sort(a+1,a+cnt+1);
    	siz=std::unique(a+1,a+cnt+1)-a-1;
    	for(int i=1;i<=n;i++) {
    		if(op[i].opt!=4) {
    			op[i].x=std::lower_bound(a+1,a+siz+1,op[i].x)-a;
    		}
    	}
    	return;
    }
    

    插入和删除

    插入和删除我们可以用一个函数实现,此时我们需要引入一个参数$delta$,通过将值设定为$pm 1$来控制插入和删除。

    void Update(int o,int l,int r,int x,int delta) {
    	sum[o]+=delta;
    	if(l==r) {
    		return;
    	}
    	if(x<=mid) {
    		Update(ls,l,mid,x,delta);
    	}
    	else {
    		Update(rs,mid+1,r,x,delta);
    	}
    }
    

    K-th(查询排名为k的数)

    int Kth(int o,int l,int r,int x) {
    	if(l==r) {
    		return l;
    	}
    	if(x<=sum[ls]) {
    		return Kth(ls,l,mid,x);
    	}
    	else {
    		return Kth(rs,mid+1,r,x-sum[ls]);
    	}
    }
    

    查询某数x的排名(比x小的数的个数+1)

    int Rank(int o,int l,int r,int x) {
    	if(l==r) {
    		return 1;
    	}
    	if(x<=mid) {
    		return Rank(ls,l,mid,x);
    	}
    	else {
    		return Rank(rs,mid+1,r,x)+sum[ls];
    	}
    }
    

    前驱与后继

    两者都是用$Kth$和$Rank$实现的,但是具体细节会有一点点不同,这个不是很好说明,所以我用下面这个图来解释:

    pre=a[Kth(1,1,siz,Rank(1,1,siz,op[i].x)-1)];
    suc=a[Kth(1,1,siz,Rank(1,1,siz,op[i].x+1))];
    

    板子

    板子我是用$namespace$写的,放在这方便以后用。

    #define N 100010
    #define mid ((l+r)>>1)
    #define ls (o<<1)
    #define rs (o<<1|1)
    
    int n,cnt,siz;
    int a[N],sum[N<<2];
    
    struct node {
    	int opt,x;
    }op[N];
    
    namespace Weight_Segment_Tree {
    	void Read() {
    		scanf("%d",&n);
    		for(int i=1;i<=n;i++) {
    			op[++tot].opt=1;
    			scanf("%d",&op[tot].x);
    			if(op[tot].opt!=4) {
    				a[++cnt]=op[tot].x;
    			}
    			if(i&1) {
    				op[++tot]=(node){4,(i>>1)+1};
    			}
    		}
    		return;
    	}
    
    	void Init() {
    		std::sort(a+1,a+cnt+1);
    		siz=std::unique(a+1,a+cnt+1)-a-1;
    		for(int i=1;i<=n;i++) {
    			if(op[i].opt!=4) {
    				op[i].x=std::lower_bound(a+1,a+siz+1,op[i].x)-a;
    			}
    		}
    		return;
    	}
    
    	void Update(int o,int l,int r,int x,int delta) {
    		sum[o]+=delta;
    		if(l==r) {
    			return;
    		}
    		if(x<=mid) {
    			Update(ls,l,mid,x,delta);
    		}
    		else {
    			Update(rs,mid+1,r,x,delta);
    		}
    	}
    
    	int Kth(int o,int l,int r,int x) {
    		if(l==r) {
    			return l;
    		}
    		if(x<=sum[ls]) {
    			return Kth(ls,l,mid,x);
    		}
    		else {
    			return Kth(rs,mid+1,r,x-sum[ls]);
    		}
    	}
    
    	int Rank(int o,int l,int r,int x) {
    		if(l==r) {
    			return 1;
    		}
    		if(x<=mid) {
    			return Rank(ls,l,mid,x);
    		}
    		else {
    			return Rank(rs,mid+1,r,x)+sum[ls];
    		}
    	}
    
    	void Solve() {
    		for(int i=1;i<=tot;i++) {
    			switch(op[i].opt) {
    				case 1:
    					Update(1,1,siz,op[i].x,1);
    					break;
    				case 2:
    					Update(1,1,siz,op[i].x,-1);
    					break;
    				case 3:
    					printf("%d
    ",Rank(1,1,siz,op[i].x));
    					break;
    				case 4:
    					printf("%d %d
    ",Kth(1,1,siz,op[i].x),a[Kth(1,1,siz,op[i].x)]);
    					break;
    				case 5:
    					printf("%d
    ",a[Kth(1,1,siz,Rank(1,1,siz,op[i].x)-1)]);
    					break;
    				case 6:
    					printf("%d
    ",a[Kth(1,1,siz,Rank(1,1,siz,op[i].x+1))]);
    					break;
    			}
    		}
    		return;
    	}
    }
    
  • 相关阅读:
    python基础一 day41 IO模型 非阻塞IO
    python基础一 day41 协程
    python基础一 day41 复习
    python基础一 day40 条件 定时器 队列 线程池
    python基础一 day40 线程锁 信号量 事件
    第三章
    第二章
    第一章
    计算机基础知识
    scrapy安装方法
  • 原文地址:https://www.cnblogs.com/luoshui-tianyi/p/13469441.html
Copyright © 2020-2023  润新知