虽然每次给一个区间,但是可以看作在区间内进行数个点操作,同样数列下标是动态变化的,如果我们将每个字符出现看作1,被删除看作0,则通过统计前缀和就能轻松计算出两个端点的位置了!这正是经典的树状数组操作

需要注意的是,即使每次找到了两个端点,如果只是朴素总左到右遍历会TLE,所以可以给每个字符开一个set,每个set储存字符出现的位置。

 #include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <map>
#include <set>
#include <vector>
#include <algorithm>
#pragma warning ( disable : 4996 )
using namespace std; int Max( int a, int b ) { return a>b?a:b; }
int Min( int a, int b ) { return a>b?b:a; }
int lowbit( int x ) { return x&-x; } const int inf = 0x3f3f3f3f;
const int maxn = 2e5+; set<int> pos[];
set<int>::iterator it, it2;
char str[maxn];
int istr[maxn];
bool isdel[maxn]; int len, q; int getI( char c )
{
if( c >= 'a' && c <= 'z' ) return c-'a';
if( c >= 'A' && c <= 'Z' ) return c-'A'+;
if( c >= '' && c <= '' ) return c-''+;
} int sum( int x )
{
int ret = ;
while( x > )
{ ret += istr[x]; x -= lowbit(x); }
return ret;
} void add( int x, int d )
{
while( x <= len )
{ istr[x] += d; x += lowbit(x); }
} int find( int s )
{
int mid, lhs = , rhs = len;
int tmp;
while ( lhs <= rhs )
{
mid = (lhs+rhs)>>;
tmp = sum(mid);
if ( tmp >= s ) rhs = mid-;
else lhs = mid+;
}
return lhs;
} void change( int l, int r, char c )
{
int p = getI(c);
it = pos[p].lower_bound(l);
while ( it!=pos[p].end() && *it<=r )
{
isdel[(*it)] = true;
add((*it), -);
it2 = it; it++;
pos[p].erase(it2);
}
} int main()
{
cin >> len >> q;
scanf("%s", str+); for ( int i = ; i <= len; i++ )
{
add(i,);
int p = getI(str[i]);
pos[p].insert(i);
} int x, y;
char c;
for ( int i = ; i <= q; i++ )
{
scanf( "%d %d %c", &x, &y, &c );
x = find(x); y = find(y);
change( x, y, c );
} for( int i = ; i <= len; i++ )
if( !isdel[i] )
printf( "%c", str[i] ); printf("\n");
return ;
}

我们看到区间操作,自然就会想到线段树,但是数列下标是动态变换的,乍一看似乎线段树就没有用武之地了。实际仔细想想,线段树也可以动态统计从哪个区间开始操作,相比普通线段树只是在每次操作前要计算新的下标到哪了,实际上每个节点管辖的范围是始终不变的,变的只是范围内字符的个数size,每次操作前通过这个size找到对应的左端点和右端点就行了。

 //线段树
#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <map>
#include <vector>
#include <algorithm>
#pragma warning ( disable : 4996 )
using namespace std; int Max( int a, int b ) { return a>b?a:b; }
int Min( int a, int b ) { return a>b?b:a; } const int inf = 0x3f3f3f3f;
const int maxn = 2e5+; struct tree {
int size, lhs, rhs;
int clu[];
}t[maxn<<];
char str[maxn]; int getI( char c )
{
if( c >= 'a' && c <= 'z' ) return c-'a';
if( c >= 'A' && c <= 'Z' ) return c-'A'+;
if( c >= '' && c <= '' ) return c-''+;
} char getC( int i )
{
if( i >= && i <= ) return 'a'+i;
if( i >= && i <= ) return 'A'+i-;
if( i >= && i <= ) return ''+i-;
} void pushUp( int index )
{
t[index].size = t[index<<].size + t[index<<|].size;
for ( int i = ; i < ; i++ )
t[index].clu[i] = t[index<<].clu[i] + t[index<<|].clu[i];
} void build( int l, int r, int index )
{
t[index].lhs = l; t[index].rhs = r;
if( l == r )
{ t[index].size = ; t[index].clu[getI(str[l-])] = ; return; }
int mid = (l+r)>>;
build(l, mid, index<<);
build(mid+, r, index<<|);
pushUp(index);
} int find( int index, int x )
{
int l = t[index].lhs, r = t[index].rhs;
if( l == r ) return l;
if( t[index<<].size >= x ) return find( index<<, x );
else return find( index<<|, x-t[index<<].size );
} void change( int index, int l, int r, int x )
{
int L = t[index].lhs, R = t[index].rhs;
if ( r < L || l > R ) return;
if ( !t[index].clu[x] ) return;
if ( L == R ) { t[index].size--; t[index].clu[x]--; return; }
change( index<<, l, r, x );
change( index<<|, l, r, x );
t[index].size = t[index<<].size + t[index<<|].size;
t[index].clu[x] = t[index<<].clu[x] + t[index<<|].clu[x];
} void print( int i )
{
int L=t[i].lhs,R=t[i].rhs;
if ( L==R )
{
for ( int j = ; j < ; j++ )
if ( t[i].clu[j] ) printf("%c",getC(j));
return;
}
print(i<<);
print(i<<|); } int main()
{
int len, q;
cin >> len >> q;
scanf("%s", str);
build(, len, ); int x, y;
char c;
for ( int i = ; i <= q; i++ )
{
scanf( "%d %d %c", &x, &y, &c );
int l = find( , x );
int r = find( , y );
change( , l, r, getI(c) );
}
print();
printf("\n");
return ;
}

Codeforces 899F Letters Removing 线段树/树状数组的更多相关文章

  1. codeforces 899F Letters Removing set+树状数组

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

  2. 899F - Letters Removing

    Codeforces 899F - Letters Removing 思路:考虑一下怎么找到输入的l和r在原来串中的位置,我们想到用前缀和来找,一开始所有位置都为1,删掉后为0,那么前缀和为l的位置就 ...

  3. Codeforces 889F Letters Removing(二分 + 线段树 || 树状数组)

    Letters Removing 题意:给你一个长度为n的字符串,然后进行m次删除操作,每次删除区间[l,r]内的某个字符,删除后并且将字符串往前补位,求删除完之后的字符串. 题解:先开80个set ...

  4. CodeForces -163E :e-Government (AC自动机+DFS序+树状数组)

    The best programmers of Embezzland compete to develop a part of the project called "e-Governmen ...

  5. Codeforces 899 F. Letters Removing (二分、树状数组)

    题目链接:Letters Removing 题意: 给你一个长度为n的字符串,给出m次操作.每次操作给出一个l,r和一个字符c,要求删除字符串l到r之间所有的c. 题解: 看样例可以看出,这题最大的难 ...

  6. Codeforces Round #424 (Div. 2, rated, based on VK Cup Finals) Problem E (Codeforces 831E) - 线段树 - 树状数组

    Vasily has a deck of cards consisting of n cards. There is an integer on each of the cards, this int ...

  7. Codeforces Round #225 (Div. 1) C. Propagating tree dfs序+ 树状数组或线段树

    C. Propagating tree Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://codeforces.com/contest/383/p ...

  8. codeforces 540E 离散化技巧+线段树/树状数组求逆序对

    传送门:https://codeforces.com/contest/540/problem/E 题意: 有一段无限长的序列,有n次交换,每次将u位置的元素和v位置的元素交换,问n次交换后这个序列的逆 ...

  9. CodeForces 173E Camping Groups 离线线段树 树状数组

    Camping Groups 题目连接: http://codeforces.com/problemset/problem/173/E Description A club wants to take ...

随机推荐

  1. android 中的一些小问题

    1 TextView 在TableRow 中占满一行 要为TextView设置 android:layout_weight="1" 这个属性 2

  2. Ubuntu vi命令

    最近在使用ubuntu,在linux下,要编辑文件或者其他的文本文件,哪那么一个ubuntu linux下的强大的文本编辑工具就不得不提了,那就是VI编辑器.下面把VI常用到的命令行贴出来. :w  ...

  3. idea-----使用相关快捷键

    1.快速格式化代码:Ctrl+Alt+L 2.快速引入get.set方法:ALT+insert 3.win 10锁屏:win+L 4.查找接口实现类的快捷键:ctrl+alt+b

  4. 日志服务Python消费组实战(二):实时分发数据

    场景目标 使用日志服务的Web-tracking.logtail(文件极简).syslog等收集上来的日志经常存在各种各样的格式,我们需要针对特定的日志(例如topic)进行一定的分发到特定的logs ...

  5. MaxCompute安全管理指南-案例篇

    通过<MaxCompute安全管理-基础篇>了解到MaxCompute和DataWorks的相关安全模型.两个产品安全方面的关联,以及各种安全操作后,本篇主要给出一些安全管理案例,给安全管 ...

  6. iOS开发CoreData的多表关联

    1.多表关联 多表关联,对SQL 数据库的操作,在一张表的数据中可以引用另外一张表里的数据.通过 Entity 实体中的 Relationships 来实现,比起传统的 SQL 数据库来,更加简单. ...

  7. mac下安装Python的工具包pip

    1. 在终端下输入 sudo easy_install pip  password:输入电脑密码 Finished processing dependencies for pip 表示安装完成 boe ...

  8. Docker系列(十六):搭建Openshift环境

    目的: 搭建Linux下的Openshift环境. 参考资料: 开源容器云OpenShift 构建基于Kubernetes的企业应用云平台 ,陈耿 ,P253 ,2017.06 .pdf 下载地址:h ...

  9. day 40 MySQL之视图、触发器、事务、存储过程、函数

    MySQL之视图.触发器.事务.存储过程.函数   阅读目录 一 视图 二 触发器 三 事务 四 存储过程 五 函数 六 流程控制 MySQL这个软件想将数据处理的所有事情,能够在mysql这个层面上 ...

  10. PAT甲级——A1084 Broken Keyboard

    On a broken keyboard, some of the keys are worn out. So when you type some sentences, the characters ...