2014-3-15-高级打字机type(可持久化线段树)

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

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

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

【样例输入】
7
T a
T b
T c
Q 2
U 2
T c
Q 2
【样例输出】
b
c
【数据范围】
对于40%的数据 n<=200;
对于100%的数据 n<=100000;保证Undo操作不会撤销Undo操作。
< 高级挑战>
对于200%的数据 n<=100000;Undo操作可以撤销Undo操作。
< IOI挑战>
必须使用在线算法完成该题。


好像还是IOI2012的
其实这题很水,100分其实一个线段树就好了,每个节点记录一下区间中有多少字母,然后查询就像权值线段树查第k大那样就好了。
然后200分就如题了,可持久化线段树再加上前面的做法。
这题真的一眼秒。
代码:(是hzwer代码时间的1/4)

#include<cstdio>
#include<cstring>
#include<iostream>
#include<cmath>
#include<algorithm>
#include<cstdlib>
#define ll long long
using namespace std;
inline int read(){
    int x=0;char ch=' ';int f=1;
    while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
    if(ch=='-')f=-1,ch=getchar();
    while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
    return x*f;
}
struct node{
    int ls,rs,size;
    char c;
}t[100001*30];
int m,n,tot;
int root[100001];
inline void build(int &now,int l,int r){
    now=++tot;
    if(l==r)return;
    int mid=(l+r)>>1;
    build(t[now].ls,l,mid);
    build(t[now].rs,mid+1,r);
}
inline void insert(int &now,int pre,int l,int r,int pos,char c){
    now=++tot;
    t[now]=t[pre];
    if(c>='a'&&c<='z')t[now].size++;
    if(l==r){t[now].c=c;return;}
    int mid=(l+r)>>1;
    if(pos<=mid)insert(t[now].ls,t[pre].ls,l,mid,pos,c);
    else insert(t[now].rs,t[pre].rs,mid+1,r,pos,c);
}
inline char query(int now,int l,int r,int x){
    if(l==r)return t[now].c;
    int mid=(l+r)>>1;
    int lsize=t[t[now].ls].size;
    if(x<=lsize)return query(t[now].ls,l,mid,x);
    else return query(t[now].rs,mid+1,r,x-lsize);
}
int main(){
    freopen("type.in","r",stdin);
    freopen("type.out","w",stdout);
    m=read();
    for(int i=1;i<=m;i++){
        char ch[3];
        int x;
        scanf("%s",ch);
        if(ch[0]=='T'){
            scanf("%s",ch);
            n++;
            insert(root[n],root[n-1],1,m,n,ch[0]);
        }
        else if(ch[0]=='U'){
            x=read();
            n++;
            insert(root[n],root[n-x-1],1,m,m,48);
        }
        else{
            x=read();
            ch[0]=query(root[n],1,m,x);
            printf("%s\n",ch);
        }
    }
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值