codeforces 899F 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]区间,要求删除其中所有的某种字符。

 

 

题解:

看到这道题我想用      树状数组+链表解决,但是由于链表顺序查找太慢,会被极端数据卡掉,可以用siz(字符集大小)个set代替(明明就是楼主脑洞错了嘛)。

 

下面开始正经的正解

正解: 树状数组+平衡树(set)

用平衡树可以轻而易举的找到对应区间的字符(upper_bound 或 lower_bound)。

但是由于删除,区间是在移动的,如何维护?

树状数组即可,起始前 i 个的累加和是 i ,如果删除 j 就把 j 位置上的 1 减去。

那么前 i 个的累加和就是第 i 个字符现在的位置。但是我们的需要是找到现在第 i 个字符原来的位置 ,这个操作树状数组也可以做而且是log级的。

详见代码。

那么问题就圆满解决了,对了,最后别忘了吧set里面剩下的所有字符都拿出来排序输出。

 1 /*
 2 Welcome Hacking
 3 Wish You High Rating
 4 */
 5 #include<iostream>
 6 #include<cstdio>
 7 #include<cstring>
 8 #include<ctime>
 9 #include<cstdlib>
10 #include<algorithm>
11 #include<cmath>
12 #include<string>
13 #include<set>
14 using namespace std;
15 int read(){
16     int xx=0,ff=1;char ch=getchar();
17     while(ch>'9'||ch<'0'){if(ch=='-')ff=-1;ch=getchar();}
18     while(ch>='0'&&ch<='9'){xx=(xx<<3)+(xx<<1)+ch-'0';ch=getchar();}
19     return xx*ff;
20 }
21 set<int>s[128];
22 set<int>::iterator it,iter;
23 const int maxn=200010;
24 int N,M,temp;
25 struct BIT{
26     int b[maxn];
27     void clear()
28     {memset(b,0,sizeof(b));}
29     inline int lowbit(int x)
30     {return x&(-x);}
31     void upd(int x,int p){
32         while(x<=N){
33             b[x]+=p;
34             x+=lowbit(x);
35         }
36     }
37     int query(int x){
38         int re=0;
39         while(x){
40             re+=b[x];
41             x-=lowbit(x);
42         }
43         return re;
44     }
45     int lower_bound(int v){
46         int x=0,sum=0;
47         for(int i=(1<<17);i;i>>=1)
48             if(i+x<=N&&sum+b[i+x]<v)
49                 sum+=b[x+=i];
50         return x+1;
51     }
52 }bit;
53 struct my{
54     int p;
55     char c;
56     bool friend operator<(const my&A,const my&B)
57     {return A.p<B.p;}
58 }m[maxn];
59 int cnt=0;
60 int main(){
61     //freopen("in.txt","r",stdin);
62     N=read(),M=read();
63     char ch;int t1,t2;
64     for(int i=1;i<=N;i++){
65         ch=getchar();
66         s[ch].insert(i);
67         bit.upd(i,1);
68     }
69     while(M--){
70         t1=read(),t2=read();ch=getchar();
71         t1=bit.lower_bound(t1),t2=bit.lower_bound(t2);
72         it=s[ch].lower_bound(t1);
73         while(it!=s[ch].end()&&(*it)<=t2){
74             bit.upd(*it,-1);
75             s[ch].erase(it++);
76         }
77     }
78     for(char i='0';i<='9';i++)
79         for(it=s[i].begin();it!=s[i].end();it++)
80             m[++cnt].c=i,m[cnt].p=*it;
81     for(char i='a';i<='z';i++)
82         for(it=s[i].begin();it!=s[i].end();it++)
83             m[++cnt].c=i,m[cnt].p=*it;
84     for(char i='A';i<='Z';i++)
85         for(it=s[i].begin();it!=s[i].end();it++)
86             m[++cnt].c=i,m[cnt].p=*it;
87     sort(m+1,m+1+cnt);
88     for(int i=1;i<=cnt;i++)
89         printf("%c",m[i].c);
90     return 0;
91 }
View Code

 

 

 

 

转载于:https://www.cnblogs.com/lzhAFO/p/8306107.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值