洛谷P1383 高级打字机(主席树)

本题重要的一个操作就是撤销之前的操作,并且可以撤销已经撤销的操作

所以我们可以使用主席树这种数据结构来维护,如果撤销,就是将当前版本指向指定位置的版本

这题其实没有建树的必要,但是我习惯建树,我们需要一个len数组和一个pos变量记录有多少个版本以及如果插入应该在哪个位置插入,这样只需线段树就能解决

#include<iostream>
#include<cstdio>
#include<string>
#include<queue>
using namespace std;
typedef long long ll;
const int N=1e5+10;
int idx;
int len[N];
int pos;
int n;
int root[N];
struct node{
    int l,r;
    char num;
}tr[N*32];
int build(int l,int r){
    int q=++idx;
    if(l==r){
        return q;
    }
    int mid=l+r>>1;
    tr[q].l=build(l,mid);
    tr[q].r=build(mid+1,r);
    return q;
}
int insert(int p,int l,int r,char c,int size){
    int q=++idx;
    tr[q]=tr[p];
    if(l==r){
        tr[q].num=c;
        return q;
    }
    int mid=l+r>>1;
    if(size<=mid)
    tr[q].l=insert(tr[p].l,l,mid,c,size);    
    else
    tr[q].r=insert(tr[p].r,mid+1,r,c,size);
    return q;
}
void query(int q,int l,int r,int size){
    if(l==r){
        cout<<tr[q].num<<endl;
        return ;
    }
    int mid=l+r>>1;
    if(size<=mid)
    query(tr[q].l,l,mid,size);
    else
    query(tr[q].r,mid+1,r,size);
}
int main(){
    int i;
    cin>>n;
    root[0]=build(1,n);
    for(i=1;i<=n;i++){
        string s;
        cin>>s;
        if(s=="T"){
            char c;
            cin>>c;
            ++pos;
            len[pos]=len[pos-1]+1;
            root[pos]=insert(root[pos-1],1,n,c,len[pos-1]+1);
        }
        else if(s=="U"){
            int x;
            cin>>x;
            ++pos;
            root[pos]=root[pos-x-1];
            len[pos]=len[pos-x-1];
        }
        else{
            int x;
            cin>>x;
            query(root[pos],1,n,x);
        }
    }
} 
View Code

 

posted @ 2020-02-06 14:39  朝暮不思  阅读(182)  评论(0编辑  收藏  举报