虽然每次给一个区间,但是可以看作在区间内进行数个点操作,同样数列下标是动态变化的,如果我们将每个字符出现看作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. 基础数据类型汇总补充,python集合与深浅拷贝

    一.基础数据类型汇总补充 1.查看str所有方法方式 2.列表:在循环中删除元素,易出错或报错(飘红) lis = [11,22,33,44,55] # for i in range(len(lis) ...

  2. FineUI使用记录

    @{ ViewBag.Title = "Grid/Grid"; var F = Html.F();} @section body { @(F.Grid().IsFluid(true ...

  3. Java编译与反编译命令记录

    1.首先进入java文件所在的地址 1) e:/ 2) dir     (显示所有文件) 3) cd eclipse-workspace 2.使用javac命令编译Test.java文件,得到Test ...

  4. iOS开发系列-NSOperation

    概述 NSOperation是基于GCD的封装更加面向对象,在使用上也是有任务跟队列的概念,分别对应两个类NSOperation .NSOperationQueue NSOperation和NSOpe ...

  5. LINUX挂接Windows文件共享

    Windows网络共享的核心是SMB/CIFS,在linux下要挂接(mount)windows的磁盘共享,就必须安装和使用samba 软件包.现在流行的linux发行版绝大多数已经包含了samba软 ...

  6. 跟我一起使用create-react-app脚手架搭建vw-layout解决方案

    之前也是看过大漠的vw适配Vue-cli,我自己写H5,还有使用vue做项目的时候,会搭建大漠博客中的那一套. 现在在github上面,看见了一位博主使用create-react-app也是用vw适配 ...

  7. Android开发 控件阴影详情

    如何给控件设置阴影? <com.google.android.material.tabs.TabLayout android:id="@+id/tablayout" andr ...

  8. soj98 卡牌

    题意:一共有n张牌,每张牌有三个属性ai,bi,ci.问在属性上限为A,B,C的所有牌中有多少张牌满足至少有两个属性可以完全压制(严格大于)那n张牌? n<=50W. 标程: #include& ...

  9. js怎样把URL链接的参数截取出来

    有时候,A页面参数需要传递到B页面,则把参数拼接到跳转B页面的url上,这时怎样在另一个页面截取A页面传递的参数呢,主要代码如下 /** * 获取指定的URL参数值 URL:http://www.qu ...

  10. Ubuntu 快速安装配置Odoo 12

    Odoo 12预计将于今年10月正式发布,这是一次大版本更新,带来了一些不错的新特性,如 文件管理系统(DMS) 用户表单中新增字段(Internal user, Portal, Public) HR ...