题目大意:
题目链接:
洛谷:https://www.luogu.org/problemnew/show/P1383
JZOJ:https://jzoj.net/senior/#main/show/3794
要求一种数据结构满足这样的操作:
- :在文章末尾打下一个小写字母。
- :撤销最后的次修改操作。
- :询问当前文章中第个字母并输出。
思路:
吐槽
我是不是可以去IOI了XD
这道题很显然是用主席树维护这个序列。干脆直接开一个长度为的主席树。每一个叶子节点储存这个节点的字母。这样虽然会大大增加空间但是不会MLE啊XD
主席树的基础题吧。对于每一个操作,新开一个主席树。对于每一个操作,把第个主席树抠到第个主席树中。对于每一个操作,直接输出第个主席树的第位即可。
时间复杂度,空间复杂度
代码:
#include <cstdio>
#include <iostream>
using namespace std;
const int N=100010;
int T,tot,sum[N],cnt,x,root[N];
char ch;
struct Tree
{
int ls,rs;
char c;
}tree[N*20];
int build(int l,int r)
{
int p=++tot;
if (l<r)
{
int mid=(l+r)/2;
tree[p].ls=build(l,mid);
tree[p].rs=build(mid+1,r);
}
return p;
}
int add(int now,int l,int r,int k,char val) //插入
{
int p=++tot;
tree[p]=tree[now];
if (l==r) tree[p].c=val;
else
{
int mid=(l+r)/2;
if (k<=mid) tree[p].ls=add(tree[now].ls,l,mid,k,val);
else tree[p].rs=add(tree[now].rs,mid+1,r,k,val);
}
return p;
}
char ask(int x,int l,int r,int k) //询问
{
if (l==k&&r==k) return tree[x].c; //找到
int mid=(l+r)/2;
if (k<=mid) return ask(tree[x].ls,l,mid,k);
else return ask(tree[x].rs,mid+1,r,k);
}
int main()
{
scanf("%d",&T);
root[0]=build(1,N);
while (T--)
{
cin>>ch;
if (ch=='T')
{
cin>>ch;
cnt++;
sum[cnt]=sum[cnt-1]+1;
root[cnt]=add(root[cnt-1],1,N,sum[cnt],ch);
}
else if (ch=='U')
{
scanf("%d",&x);
cnt++;
root[cnt]=root[cnt-x-1];
sum[cnt]=sum[cnt-x-1];
}
else
{
scanf("%d",&x);
putchar(ask(root[cnt],1,N,x));
putchar(10);
}
}
return 0;
}
再次吐槽
JZOJ这道题可以用Pascal的滚动数组+ansistring过掉…