Codeforces Round #452 (Div. 2)-F-Letters Removing(树状数组+set+二分)

F. Letters Removing
time limit per test
2 seconds
memory limit per test
256 megabytes
input
standard input
output
standard output

Petya has a string of length n consisting of small and large English letters and digits.

He performs m operations. Each operation is described with two integers l and r and a character c: Petya removes from the string all characters c on positions between l and r, inclusive. It's obvious that the length of the string remains the same or decreases after each operation.

Find how the string will look like after Petya performs all m operations.

Input

The first string contains two integers n and m (1 ≤ n, m ≤ 2·105) — the length of the string and the number of operations.

The second line contains the string of length n, consisting of small and large English letters and digits. Positions in the string are enumerated from 1.

Each of the next m lines contains two integers l and r (1 ≤ l ≤ r), followed by a character c, which is a small or large English letter or a digit. This line describes one operation. It is guaranteed that r doesn't exceed the length of the string s before current operation.

Output

Print the string Petya will obtain after performing all m operations. If the strings becomes empty after all operations, print an empty line.

Examples
input
4 2
abac
1 3 a
2 2 c
output
b
input
3 2
A0z
1 3 0
1 1 z
output
Az
input
10 4
agtFrgF4aF
2 5 g
4 9 F
1 5 4
1 7 a
output
tFrg4
input
9 5
aAAaBBccD
1 4 a
5 6 c
2 3 B
4 4 D
2 3 A
output
AB
Note

In the first example during the first operation both letters 'a' are removed, so the string becomes "bc". During the second operation the letter 'c' (on the second position) is removed, and the string becomes "b".

In the second example during the first operation Petya removes '0' from the second position. After that the string becomes "Az". During the second operations the string doesn't change.

题意:给你一个字符串,该字符串由大小写字母和数字组成,然后有m个操作,每次操作给你 l,r,c让你将区间[l,r]中所有字符是c的给删点,然后后边自动往前补,每次操作都是度当前已更改过的字符串操作,让你输出m次操作后的字符串

题解:因为每次操作完后,很多字符已经不再原来的位置上了,这给我们下次查询带来很多不便,当然我们不能暴力改位置,我们可以考虑采用树状数组,初始时让数组中每个元素都为1,然后求和,每删掉一个字符,让该位置上的sum变为0,也就是树状数组单点更新,这样我们每次操作的l和r都可以通过二分+树状数组查询到相应的位置上,剩下的就是删点了,我们可以用set存一下每个字符所在那些位置,然后利用set的性质就能很快的删掉区间中所有的字符c。

#include<set>
#include<stdio.h>
#include<algorithm>
using namespace std;
#define maxn 200005
int n,m,sum[maxn],flag[maxn];
char str[maxn];
set<int>s[105];set<int>::iterator it;
int to(char s)
{
	if(s>='a' && s<='z')
		return s-'a'+1;
	if(s>='0' && s<='9')
		return s-'0'+26+1;
	return s-'A'+36+1;
}
void add(int x,int val)
{
	while(x<=n)
		sum[x]+=val,x+=x&-x;
}
int query(int x)
{
	int res=0;
	while(x)
		res+=sum[x],x-=x&-x;
	return res;
}
void update(int x)
{
	while(x<=n)
		sum[x]--,x+=x&-x;
}
int find(int x)
{
	int l=1,r=n,mid;
	while(l<r)
	{
		mid=(l+r)/2;
		if(query(mid)>=x)
			r=mid;
		else
			l=mid+1;
	}
	return r;
}
int main(void)
{
	scanf("%d%d%s",&n,&m,str+1);
	for(int i=1;i<=n;i++) add(i,1);
	for(int i=1;i<=n;i++)
	{
		int x=to(str[i]);
		s[x].insert(i);
	}
	while(m--)
	{
		int l,r; char c;
		scanf("%d%d %c",&l,&r,&c);
		int x=to(c);l=find(l);r=find(r);
		//printf("%d %d\n",l,r);
		it=s[x].lower_bound(l);
		while(it!=s[x].end() && *it<=r)
		{
			flag[*it]=1;
			update(*it);
			s[x].erase(it++);
		}
	}
	for(int i=1;i<=n;i++)
		if(flag[i]==0)
			printf("%c",str[i]);
	printf("\n");
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值