zoukankan      html  css  js  c++  java
  • 【洛谷P3919】(模板)可持久化数组(可持久化线段树/平衡树)

    题目链接

    (模板)可持久化数组(可持久化线段树/平衡树)

    题目背景

    UPDATE : 最后一个点时间空间已经放大
    标题即题意
    有了可持久化数组,便可以实现很多衍生的可持久化功能(例如:可持久化并查集)

    题目描述

    如题,你需要维护这样的一个长度为(N)的数组,支持如下几种操作

    1. 在某个历史版本上修改某一个位置上的值
    2. 访问某个历史版本上的某一位置的值

    此外,每进行一次操作(对于操作(2),即为生成一个完全一样的版本,不作任何改动),就会生成一个新的版本。版本编号即为当前操作的编号(从(1)开始编号,版本(0)表示初始状态数组)

    输入格式

    输入的第一行包含两个正整数(N,M),分别表示数组的长度和操作的个数。
    第二行包含(N)个整数,依次为初始状态下数组各位的值(依次为(a_i)(1 leq i leq N))。
    接下来(M)行每行包含(3)(4)个整数,代表两种操作之一((i)为基于的历史版本号):

    1. 对于操作(1),格式为(v_i 1 {loc}_i {value}_i),即为在版本(v_i)的基础上,将(a_{{loc}_i})修改为({value}_i)
    2. 对于操作(2),格式为(v_i 2 {loc}_i),即访问版本(v_i)中的(a_{{loc}_i})的值,生成一样版本的对象应为(v_i)

    输出格式

    输出包含若干行,依次为每个操作2的结果。

    样例输入

    5 10
    59 46 14 87 41
    0 2 1
    0 1 1 14
    0 1 1 57
    0 1 1 88
    4 2 4
    0 2 5
    0 2 4
    4 2 1
    2 2 2
    1 1 5 91
    

    样例输出

    59
    87
    41
    87
    88
    46
    

    说明/提示

    数据规模:
    对于(30\%)的数据:(1 leq N, M leq {10}^3)
    对于(50\%)的数据:(1 leq N, M leq {10}^4)
    对于(70\%)的数据:(1 leq N, M leq {10}^5)
    对于(100\%)的数据:(1 leq N, M leq {10}^6, 1 leq {loc}_i leq N, 0 leq v_i < i, -{10}^9 leq a_i, {value}_i leq {10}^9)
    经测试,正常常数的可持久化数组可以通过,请各位放心
    数据略微凶残,请注意常数不要过大
    另,此题I/O量较大,如果实在TLE请注意I/O优化
    询问生成的版本是指你访问的那个版本的复制
    样例说明:
    一共(11)个版本,编号从(0-10),依次为:

    • (0) : 59 46 14 87 41
    • (1) : 59 46 14 87 41
    • (2) : 14 46 14 87 41
    • (3) : 57 46 14 87 41
    • (4) : 88 46 14 87 41
    • (5) : 88 46 14 87 41
    • (6) : 59 46 14 87 41
    • (7) : 59 46 14 87 41
    • (8) : 88 46 14 87 41
    • (9) : 14 46 14 87 41
    • (10) : 59 46 14 87 91

    题解

    很明显的一道数据结构板题,但是我只能从版本的要求看出是主席树,而且感觉我的建树方法会有浪费,还不知道怎么用平衡树做这道题,总的来说,我好菜啊。
    因为每次修改操作是基于先前几次操作的版本进行操作的,所以我们可以把初始序列的信息存入第一棵线段树,然后每次修改(询问)的时候新建一棵树就好了。
    其实对于每棵线段树,我们只要在它的叶子节点存入它的值就好了,而非叶子节点只需要存区间和左右儿子就好了。(这样的话会在非叶子节点上浪费很多空间,但是我也不知道有没有更好的办法)
    接下来就是主席树的基本操作了,修改点值的时候,新建这个点以及它的所有祖先就好了。
    如果不会主席树的话,可以到这里,看主席树的详解。
    上代码:

    #include<bits/stdc++.h>
    using namespace std;
    int n,m;
    int v,lo,val,x;
    int a[1000009];
    int ubb;
    int kk;
    int rt[1000009];
    struct aa{
    	int l,r;
    	int s;
    	int cd[2];
    }p[30000009];
    int len;
    void init(int u,int l,int r){
    	p[u].l=l;p[u].r=r;
    	if(l==r){
    		p[u].s=a[l];
    		return;
    	}
    	int mid=(l+r)/2;
    	if(l<=mid) init(p[u].cd[0]=++len,l,mid);
    	if(mid+1<=r) init(p[u].cd[1]=++len,mid+1,r);
    }
    int lrt;
    void dfs(int u,int x,int s){
    	int mid=(p[u].l+p[u].r)/2;
    	if(p[u].l==p[u].r){
    		p[u].s=val;
    		return;
    	}
    	len++;
    	if(x<=mid){
    		p[len]=p[p[u].cd[0]];
    		p[u].cd[0]=len;
    	}else{
    		p[len]=p[p[u].cd[1]];
    		p[u].cd[1]=len;
    	}
    	dfs(len,x,s);
    }
    void ask(int u,int x){
    	int mid=(p[u].l+p[u].r)/2;
    	if(p[u].l==p[u].r){
    		printf("%d
    ",p[u].s);
    		return;
    	}
    	if(x<=mid) ask(p[u].cd[0],x);
    	else ask(p[u].cd[1],x);
    }
    int main(){
    	scanf("%d%d",&n,&m);
    	for(int j=1;j<=n;j++)
    		scanf("%d",&a[j]);
    	init(rt[0]=len=1,1,n);
    	for(int j=1;j<=m;j++){
    		scanf("%d%d%d",&v,&x,&lo);
    		if(x==1){
    			scanf("%d",&val);
    			rt[++lrt]=++len;
    			p[len]=p[rt[v]];
    			dfs(len,lo,val);
    		}else{
    			rt[++lrt]=rt[v];
    			ask(rt[v],lo);
    		}
    	}
    	return 0;
    }
    
  • 相关阅读:
    iptables详解
    Linux文件结构及基本文件夹
    linux的一些常用命令
    Sql Server REPLACE函数的使用
    MSSQL复制表操作
    MSSQL2005数据库显示单一用户模式,无法进行任何操作
    linux下查看所有用户及所有用户组
    SpringMVC基础-10-拦截器
    SpringMVC基础-09-文件上传(单文件、多文件上传)
    SpringMVC基础-08-数据转换 & 数据格式化 & 数据校验
  • 原文地址:https://www.cnblogs.com/linjiale/p/12216616.html
Copyright © 2011-2022 走看看