OI操作树

Posted dudujerry

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了OI操作树相关的知识,希望对你有一定的参考价值。

操作数,一般用来做那些对数列进行添加、撤销操作的题。

 

假设一开始有一个空数列,有三个操作

(1)在数列后加一个数

(2)求数列中某位置的值

(3)撤销掉最后进行的若干次操作(1和3)

 

考虑建一棵树,1操作则为在当前节点下新加一个节点,2操作求数列k位置值,则为从根节点到当前节点k个节点的位置的节点

3操作撤销掉最后进行的k次操作则为回溯k个节点,同时记录回溯前的当前节点和回溯后的当前节点。

所以每次进行查询的时候,先从当前节点找父亲,一直找到根节点,记录节点个数,然后节点个数-k得到当前节点到要查询的节点的距离。

撤销操作的时候,父亲是1操作的节点就往上找父亲,父亲是3操作节点就跳到那个3操作回溯之前的那个“当前节点”

 

例如这道题:

总时间限制: 
10000ms
 
单个测试点时间限制: 
1000ms
 
内存限制: 
262144kB
描述

给一个空数列,有M次操作,每次操作是以下三种之一:

(1)在数列后加一个数

(2)求数列中某位置的值

(3)撤销掉最后进行的若干次操作(1和3)

输入
第一行一个正整数M。
接下来M行,每行开头是一个字符,若该字符为‘A‘,则表示一个加数操作,接下来一个整数x,表示在数列后加一个整数x;若该字符为‘Q‘,则表示一个询问操作,接下来一个整数x,表示求x位置的值;若该字符为‘U‘,则表示一个撤销操作,接下来一个整数x,表示撤销掉最后进行的若干次操作。
输出
对每一个询问操作单独输出一行,表示答案。
样例输入
9
A 1
A 2
A 3
Q 3
U 1
A 4
Q 3
U 2
Q 3
样例输出
3
4
3
提示
1<=M<=10^5,输入保证合法,且所有整数可用带符号32位整型存储。
技术图片
#include <cstdio>
#include <iostream>

const int MaxN = 100001;
int fa[MaxN];
//bool edge[MaxN][MaxN];
int n;
int V[MaxN];
int back[MaxN];

int main()

    scanf("%d",&n);
    
    int now_node;
    
    char XX;
    std::cin>>XX;
    int xx;
    scanf("%d",&xx);
    now_node = 1;
    
    int node_cnt = 1;
    V[node_cnt] = xx;
    
    for(int l = 2; l <= n; l++)
        char X;
        std::cin>>X;
        if(X == A)
            int nx;
            scanf("%d",&nx);
            V[++node_cnt] = nx;
            fa[node_cnt] = now_node;
            //edge[now_node][node_cnt] = 1;
            now_node = node_cnt;
            
        
        else if(X == U)
            int nx;
            scanf("%d",&nx);
            int last_node = now_node;
            for(int i = 1; i <= nx; i++)
                if(!back[now_node])
                    now_node = fa[now_node];
                else
                    now_node = back[now_node];
                
            
            back[now_node] = last_node;
            
        
        else if(X == Q)
            int nx;
            scanf("%d",&nx);
            
            int count = 0;
            int tmp = now_node;
            while(1)
                if(!fa[tmp])
                    break;
                
                tmp = fa[tmp];
                count++;
            
            count = count - nx;
            tmp = now_node;
            for(int i = 1; i <= count; i++)
                tmp = fa[tmp];
            
            printf("%d\n",V[tmp]);
        
    
    return 0;
View Code

 

以上是关于OI操作树的主要内容,如果未能解决你的问题,请参考以下文章

浅谈LCT

BZOJ4811[Ynoi2017]由乃的OJ 树链剖分+线段树

NOIP2017整数 线段树

可持久化算法

bzoj4811[Ynoi2017]由乃的OJ 树链剖分+线段树区间合并

codeforces 787D - Legacy 线段树优化建图,最短路