【JZOJ3794】【洛谷P1383】高级打字机【主席树】

题目大意:

题目链接:

洛谷:https://www.luogu.org/problemnew/show/P1383
JZOJ:https://jzoj.net/senior/#main/show/3794

要求一种数据结构满足这样的操作:

  1. T   x T\ x T x:在文章末尾打下一个小写字母 x x x
  2. U   x U\ x U x:撤销最后的 x x x次修改操作。
  3. Q   x Q\ x Q x:询问当前文章中第 x x x个字母并输出。

思路:

吐槽

我是不是可以去IOI了XD

这道题很显然是用主席树维护这个序列。干脆直接开一个长度为 1 0 5 10^5 105的主席树。每一个叶子节点储存这个节点的字母。这样虽然会大大增加空间但是不会MLE啊XD
主席树的基础题吧。对于每一个 T T T操作,新开一个主席树。对于每一个 U U U操作,把第 c n t − x − 1 cnt-x-1 cntx1个主席树抠到第 c n t cnt cnt个主席树中。对于每一个 Q Q Q操作,直接输出第 c n t cnt cnt个主席树的第 x x x位即可。
时间复杂度 O ( T   l o g   n ) O(T\ log\ n) O(T log n),空间复杂度 O ( n   l o g   n ) O(n \ log\ n) O(n log n)


代码:

#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过掉…

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值