P1383 高级打字机(可持久化线段树)
传送门:高级打字机
看到题目中的撤销操作就可以想到历史版本,不难想到使用可持久化线段树。
难点在于如何维护撤销操作,容易想到可以利用 \(root\) 数组。我们直接把 \(x\) 个操作前的 \(root\) 赋给当前的 \(root\),就可以保证撤销操作。
需要注意的是询问操作需要过滤掉,以保证撤销后的信息可以覆盖之前的信息。
#include<bits/stdc++.h>
using namespace std;
const int N = 100000 + 10;
struct Seg
{
int l,r;
char val;
} tree[32*N];
int root[32*N],len[32*N];
int n,tot,cnt;
int build(int p,int l,int r)
{
p = ++tot;
if(l == r) return p;
int mid = (l + r) >> 1;
tree[p].l = build(tree[p].l,l,mid);
tree[p].r = build(tree[p].r,mid + 1,r);
return p;
}
int create(int p)
{
tot++;
tree[tot] = tree[p];
return tot;
}
int modify(int p,int l,int r,int x,char v)
{
p = create(p);
if(l == r)
{
tree[p].val = v;
return p;
}
int mid = (l + r) >> 1;
if(x <= mid) tree[p].l = modify(tree[p].l,l,mid,x,v);
else tree[p].r = modify(tree[p].r,mid + 1,r,x,v);
return p;
}
char query(int p,int l,int r,int x)
{
if(l == r) return tree[p].val;
int mid = (l + r) >> 1;
if(x <= mid) return query(tree[p].l,l,mid,x);
else return query(tree[p].r,mid + 1,r,x);
}
signed main()
{
scanf("%d",&n);
root[0] = build(0,1,n);
for(int i = 1;i <= n;i++)
{
char opt;
cin >> opt;
if(opt == 'T')
{
cnt++;
char v;
cin >> v;
len[cnt] = len[cnt-1] + 1;
root[cnt] = modify(root[cnt-1],1,n,len[cnt],v);
}
else if(opt == 'U')
{
int x;
scanf("%d",&x);
cnt++;
root[cnt] = root[cnt-x-1];
len[cnt] = len[cnt-x-1];
}
else if(opt == 'Q')
{
int x;
scanf("%d",&x);
//cout << x << endl;
cout << query(root[cnt],1,n,x) << endl;
//root[i] = root[i-1];
//len[i] = len[i-1];
}
}
return 0;
}

浙公网安备 33010602011771号