zoukankan      html  css  js  c++  java
  • 可持续化线段树

    可持续化线段树,也叫主席树,很久以前【也没多久】写了一篇求区间第k大的,那时候理解不深,现在再写一个加深理解

    可持续化,具体来说就是可以访问历史版本,以实现跨时间的操作。

    怎么实现呢?
    试想我们修改线段树的时候,修改前是旧版本,修改后是新版本,想想新版本和旧版本有什么区别?
    区别就在于从根节点到被修改点的路径上的点改变了,其他的点是不变的

    那么这个时候我们新建一个根节点,对于不变的儿子指向旧版本的儿子,对于有变化的儿子就新建一个节点
    这样一来我们有每一个时刻的根节点,就可以访问到每个时刻的线段树
    空间会不会暴呢?
    每条路径只有logn个点,m次修改我们只多了mlogn个点,可以承受
    但实在空间卡得很紧时就要用指针了

    比如洛谷P3931

    下面给出指针版题解代码【并非完全是普遍的写法,由题简化】:
    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define LL long long int
    #define REP(i,n) for (int i = 1; i <= (n); i++)
    #define fo(i,x,y) for (int i = (x); i <= (y); i++)
    #define Redge(u) for (int k = head[u]; k != -1; k = edge[k].next)
    using namespace std;
    const int maxn = 1000005,maxm = 10000005,INF = 1000000000;
    
    inline int read(){
    	int out = 0,flag = 1;char c = getchar();
    	while (c < 48 || c > 57) {if (c == '-') flag = -1; c = getchar();}
    	while (c >= 48 && c <= 57) {out = out * 10 + c - 48; c = getchar();}
    	return out * flag;
    }
    
    int N,M,A[maxn];
    
    struct node{
    	int v;
    	node *ls,*rs;
    	node() {ls = rs = NULL;}
    };
    node* rt[maxn];
    int rti = 0,pos;
    
    void Build(node **u,int l,int r){
    	*u = new node;
    	if (l == r){
    		(*u)->v = A[l];
    	}else {
    		int mid = l + r >> 1;
    		Build(&(*u)->ls,l,mid);
    		Build(&(*u)->rs,mid + 1,r);
    	}
    }
    
    void change(node *pre,node **u,int l,int r,int v){
    	(*u) = new node;
    	*(*u) = *pre;
    	if (l == r){
    		(*u)->v = v;
    	}else {
    		int mid = l + r >> 1;
    		if (mid >= pos) change(pre->ls,&(*u)->ls,l,mid,v);
    		else change(pre->rs,&(*u)->rs,mid + 1,r,v);
    	}
    }
    
    int Query(node *u,int l,int r){
    	if (l == r) return u->v;
    	else {
    		int mid = l + r >> 1;
    		if (mid >= pos) return Query(u->ls,l,mid);
    		else return Query(u->rs,mid + 1,r);
    	}
    }
    
    int main()
    {
    	N = read();
    	M = read();
    	REP(i,N) A[i] = read();
    	Build(&rt[0],1,N);
    	int pre,cmd,v;
    	while (M--){
    		pre = read();
    		cmd = read();
    		pos = read();
    		if (cmd & 1){
    			v = read();
    			change(rt[pre],&rt[++rti],1,N,v);
    		}else {
    			printf("%d
    ",Query(rt[++rti] = rt[pre],1,N));
    		}
    	}
    	return 0;
    }
    

  • 相关阅读:
    就业DAY7_web服务器_tcp三次握手四次挥手,返回浏览器需要的页面http服务器
    就业DAY7_web服务器_http协议
    就业DAY6_web服务器_正则表达式
    就业DAY5_多任务_协程
    就业DAY5_多任务_进程,进程池,队列
    win10安装ubuntu系统,报错WslRegisterDistribution failed with error: 0x8007019e
    解决ubuntu与win10双系统时间不同步
    Linux常用压缩解压命令
    ubuntu添加国内源
    解决Ubuntu“下载额外数据文件失败 ttf-mscorefonts-installer”的问题 (转载)
  • 原文地址:https://www.cnblogs.com/Mychael/p/8282846.html
Copyright © 2011-2022 走看看