码迷,mamicode.com
首页 > 其他好文 > 详细

可持久化线段树(主席树)

时间:2019-08-11 11:06:56      阅读:72      评论:0      收藏:0      [点我收藏+]

标签:-o   多个   put   ==   names   区别   printf   query   rip   

其实这个模板我就花了四个晚上调试,所以代码实现能力弱是个大坑:)

思路

主席树的另一个名字叫做可持久化权值线段树,用于维护多个版本的线段树。由于开多颗线段树的话空间会炸到飞起,所以可以充分利用每棵线段树中的重复部分。比如在第i + 1的版本的末尾新增一个节点,第i + 1棵版本的线段树和第i棵线段树的区别只是rt的右儿子及其子树中的一小部分。我们就可以在每一次更新版本时,另开那些有变化的节点,并与没有变化的节点连边(我们把这称之为动态开点)。这样即可节省大量空间,查询仿照普通线段树即可,

注意事项

1、有些题目一开始一定要开一棵空树;

2、要把每一个版本的根节点开个数组存起来;

JZOJ 3794 高级打字机

Description

早苗入手了最新的高级打字机。最新款自然有着与以往不同的功能,那就是它具备撤销功能,厉害吧。
请为这种高级打字机设计一个程序,支持如下3种操作:
T x:在文章末尾打下一个小写字母x。(type操作)
U x:撤销最后的x次修改操作。(Undo操作)(注意Query操作并不算修改操作)
Q x:询问当前文章中第x个字母并输出。(Query操作)文章一开始可以视为空串。

Input

第1行:一个整数n,表示操作数量。以下n行,每行一个命令。保证输入的命令合法。

Output

每行输出一个字母,表示Query操作的答案。

Sample Input

7
T a
T b
T c
Q 2
U 2
T c
Q 2

Sample Output

bc

Data Constraint

n<=100000;Undo操作可以撤销Undo操作。

代码

#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;

const int N = 10000007;

int n, tot = 0, cnt = 0, t;
int rt[N], lson[N], rson[N], len[N];
char v[N], c;

void add(int &cur, int po, int l, int r, int last)
{
    if (!cur) cur = ++tot;
    if (l == r)
    {
        v[cur] = c;
        return;
    }
    int mid = (l + r) >> 1;
    if (po <= mid) 
        rson[cur] = rson[last], add(lson[cur], po, l, mid, lson[last]);
    if (mid + 1 <= po)
        lson[cur] = lson[last], add(rson[cur], po, mid + 1, r, rson[last]);    
}
char ask(int po, int cur, int l, int r)
{
    if (l == r) 
        return v[cur];
    int mid = (l + r) >> 1;
    if (po <= mid)
        return ask(po, lson[cur], l, mid);
    if (mid + 1 <= po)
        return ask(po, rson[cur], mid + 1, r);
}
int main()
{
    scanf("%d", &n);
    memset(rt, 0, sizeof rt);
    memset(lson, 0, sizeof lson);
    memset(rson, 0, sizeof rson);
    memset(len, 0, sizeof len);
    for (int i = 1; i <= n; i++)
    {
        char type;
        scanf(" %c", &type);
        if (type == 'T')
        {
            scanf(" %c", &c);
            len[++cnt] = len[cnt - 1] + 1;
            add(rt[cnt], len[cnt], 1, N, rt[cnt - 1]);//r在这道题中一定要是常数N哦,不然不变化的节点所代表的区间就不一样了 
        }
        if (type == 'U')
        {
            scanf("%d", &t);
            len[++cnt] = len[cnt - t - 1];
            rt[cnt] = rt[cnt - t - 1];
        }
        if (type == 'Q')
        {
            scanf("%d", &t);
            printf("%c\n", ask(t, rt[cnt], 1, N));
        }
    }
    return 0;
}

可持久化线段树(主席树)

标签:-o   多个   put   ==   names   区别   printf   query   rip   

原文地址:https://www.cnblogs.com/featherZHY/p/11334035.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!