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是根据当前的字符串来给的。是变化的。

 

POINT:

因为是变化的l,r,所以我们要把他们还原为原始位置。

用树状数组实现,先给树状数组全为1。然后删一个字符,那个字符对应的位置就是1。

那么每次给你的l和r,那就从树状数组里找到前缀和恰好是l的位置。就实现了。二分查找+树状数组查询为(logn)^2.

先用set存下每一个字符的位置。因为set是有序的,用二分查找第l个,然后遍历下去到r。全删掉。

 

 

#include <set>
#include <vector>
#include <stdio.h>
#include <string.h>
#include <iostream>
#include <algorithm>

using namespace std;
const int maxn  = 4e5+5555;
#define lowbit(x) (x&-x)
int sum[maxn];
int n,m;
int flag[maxn];
set<int>S[70];
set<int>::iterator it;
int name(char x)
{
	if(x>='a'&&x<='z'){
		return x-'a'+1;
	}else if(x>='0'&&x<='9'){
		return x-'0'+1+26;
	}else{
		return x-'A'+1+36;
	}
}
void subtract(int x)
{
	for(int i=x;i<=n;i+=lowbit(i))
		sum[i]--;
}
int query(int x)
{
	int ans=0;
	for(int i=x;i>=1;i-=lowbit(i)) ans+=sum[i];
	return ans;
}
int lb(int x)
{
	int l=1,r=n;
	while(l<r){
		int mid=(l+r)>>1;
		if(query(mid)>=x){
			r=mid;
		}else{
			l=mid+1;
		}
	}
	return r;
}
char s[maxn];
int main()
{
	scanf("%d%d",&n,&m);
	scanf("%s",s);
	for(int i=1;i<=n;i++){
		sum[i+lowbit(i)]+=++sum[i];
	}
	int l=strlen(s);
	for(int i=0;i<l;i++){
		int x=name(s[i]);
		S[x].insert(i+1);
	}
	for(int i=1;i<=m;i++){
		int l,r;char ss[22];
		scanf("%d%d%s",&l,&r,ss);
		int x=name(ss[0]);
		l=lb(l);
		r=lb(r);
		it=S[x].lower_bound(l);
		while(it!=S[x].end()&&*it<=r){
			flag[*it]=1;
			subtract(*it);
			S[x].erase(it++);
		}
	}
	for(int i=1;i<=l;i++){
		if(!flag[i]){
			printf("%c",s[i-1]);
		}
	}
	printf("\n");


}

 

 

 

 

 

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值