Codeforces 889F Letters Removing(二分 + 线段树 || 树状数组)
题意:给你一个长度为n的字符串,然后进行m次删除操作,每次删除区间[l,r]内的某个字符,删除后并且将字符串往前补位,求删除完之后的字符串。
题解:先开80个set 将每个字符对应的下标存入空间, 然后每次删除了一个字符之后就将字符串的相应位置改成一个不会产生干扰的字符(我这里使用的是'.')。 并且在线段树的相应位置标记一下。然后每次删除时候的左右区间就用2分区查找。
找到位置pos 使得 [1,pos]的值等于 pos - l, 这样就可以找到相应的区间了。原因, [1,pos]的值代表着区间[1,pos]内被删除的元素个数是多少。 pos - 向左移动的数目([1,pos]) 就是在进行前面删除操作之后并往前补位的位置了。
#include<set>
#include<iostream>
#include<string>
using namespace std;
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
const int N = 2e5+;
int n, m;
int tree[N<<];
string str, tmp;
set<int> G[];
void PushUp(int rt)
{
tree[rt] = tree[rt<<|] + tree[rt<<];
}
void Revise(int L, int l, int r, int rt)
{
if(l == r)
{
tree[rt]++;
return ;
}
int m = l+r >> ;
if(L <= m) Revise(L,lson);
else Revise(L,rson);
PushUp(rt);
}
int Query(int L, int R, int l, int r, int rt)
{
if(L <= l && r <= R)
return tree[rt];
int m = l+r >> ;
int ret = ;
if(L <=m) ret += Query(L,R,lson);
if(m < R) ret+= Query(L,R,rson);
return ret;
}
int Find_pos(int pos)
{
int l = pos, r = n;
while(l <= r)
{
int m = l+r >> ;
int num = Query(,m,,n,);
if(m == num + pos && str[m] != '.')
{
return m;
}
else if(m < num+ pos) l = m+;
else r = m - ;
}
}
int main()
{
ios::sync_with_stdio(false);
cin.tie();
cout.tie();
cin >> n >> m;
cin >> str;
set<int>::iterator it;
str = "#"+str;//将字符串往右整体移动一位
for(int i = ; i <= n; i++)
G[str[i]-''].insert(i);//将对应的位置分别存到对应的set
int l, r;
while(m--)
{
cin >> l >> r >> tmp;
if(l + tree[] > n) continue; //如果区间左端点大于有效长度
if(l == r) l = r = Find_pos(l); //那么就表示不用进行删除操作了
else {
l = Find_pos(l);
if(r + tree[] > n) r = n;
else r = Find_pos(r);
}
int pos =(int)tmp[] - '';
it = G[pos].begin();
while(it != G[pos].end())
{
int index = *it;
if(index >= l && index <= r)
{
Revise(index,,n,);
str[index] = '.';
it = G[pos].erase(it);
}
else it++;
if(index > r) break;
}
}
for(int i = ; i <= n; i++)
{
if(str[i] != '.')
cout << str[i];
}
cout << endl;
return ;
}
树状数组代码:
#include<set>
#include<iostream>
#include<string>
using namespace std;
const int N = 2e5+;
int n, m;
int tree[N];
string str, tmp;
set<int> G[];
int lowbit(int x)
{
return x&(-x);
}
void Add(int x)
{
while(x <= n)
{
tree[x]++;
x += lowbit(x);
}
}
int Query(int x)
{
int ret = ;
while(x > )
{
ret += tree[x];
x -= lowbit(x);
}
return ret;
}
int Find_pos(int pos)
{
int l = pos, r = n;
while(l <= r)
{
int m = l+r >> ;
int num = Query(m);
if(m == num + pos && str[m] != '.')
{
return m;
}
else if(m < num+ pos) l = m+;
else r = m - ;
}
}
int main()
{
ios::sync_with_stdio(false);
cin.tie();
cout.tie();
cin >> n >> m;
cin >> str;
set<int>::iterator it;
str = "#"+str;//将字符串往右整体移动一位
for(int i = ; i <= n; i++)
G[str[i]-''].insert(i);//将对应的位置分别存到对应的set
int l, r;
while(m--)
{
cin >> l >> r >> tmp;
if(l + tree[] > n) continue; //如果区间左端点大于有效长度
if(l == r) l = r = Find_pos(l);//那么就表示不用进行删除操作了
else
{
l = Find_pos(l);
if(r + tree[] > n) r = n;
else r = Find_pos(r);
} int pos = tmp[] - '';
it = G[pos].begin();
while(it != G[pos].end())
{
int index = *it;
if(index >= l && index <= r)
{
Add(index);
str[index] = '.';
it = G[pos].erase(it);
}
else it++;
if(index > r) break;
}
}
for(int i = ; i <= n; i++)
{
if(str[i] != '.')
cout << str[i];
}
cout << endl;
return ;
}
Codeforces 889F Letters Removing(二分 + 线段树 || 树状数组)的更多相关文章
- Codeforces 899F Letters Removing 线段树/树状数组
虽然每次给一个区间,但是可以看作在区间内进行数个点操作,同样数列下标是动态变化的,如果我们将每个字符出现看作1,被删除看作0,则通过统计前缀和就能轻松计算出两个端点的位置了!这正是经典的树状数组操作 ...
- Educational Codeforces Round 61 D 二分 + 线段树
https://codeforces.com/contest/1132/problem/D 二分 + 线段树(弃用结构体型线段树) 题意 有n台电脑,只有一个充电器,每台电脑一开始有a[i]电量,每秒 ...
- codeforces 899F Letters Removing set+树状数组
F. Letters Removing time limit per test 2 seconds memory limit per test 256 megabytes input standard ...
- CodeForces - 1087F:Rock-Paper-Scissors Champion(set&数状数组)
n players are going to play a rock-paper-scissors tournament. As you probably know, in a one-on-one ...
- CodeForces -163E :e-Government (AC自动机+DFS序+树状数组)
The best programmers of Embezzland compete to develop a part of the project called "e-Governmen ...
- 899F - Letters Removing
Codeforces 899F - Letters Removing 思路:考虑一下怎么找到输入的l和r在原来串中的位置,我们想到用前缀和来找,一开始所有位置都为1,删掉后为0,那么前缀和为l的位置就 ...
- Codeforces 899 F. Letters Removing (二分、树状数组)
题目链接:Letters Removing 题意: 给你一个长度为n的字符串,给出m次操作.每次操作给出一个l,r和一个字符c,要求删除字符串l到r之间所有的c. 题解: 看样例可以看出,这题最大的难 ...
- CodeForces992E 二分 + 树状数组(线段树)
http://codeforces.com/problemset/problem/992/E 题意:给定一个序列 ai ,记其前缀和序列为 si ,有 q 个询问,每次单点修改,询问是否存在一个 ...
- codeforces 1269E K Integers (二分+树状数组)
链接:https://codeforces.com/contest/1269/problem/E 题意:给一个序列P1,P2,P3,P4....Pi,每次可以交换两个相邻的元素,执行最小次数的交换移动 ...
随机推荐
- 记kepServer读写西门子PLC
在程序开发过程中为了测试方法或者验证某个属性的值是否正确 经常通过Kepserver 的 OPC Quick Client来手动置点或者读取点位 例如 这里显示的值都是经过转化后得到的十进制值,那我们 ...
- Mysql的行级锁与表级锁
在计算机科学中,锁是在执行多线程时用于强行限制资源访问的同步机制,即用于在并发控制中保证对互斥要求的满足. 在DBMS中,可以按照锁的粒度把数据库锁分为行级锁(INNODB引擎).表级锁(MYISAM ...
- Axis1.4 配置数组类型复杂对象
最近 项目对接 webservice,要求SOAP 标准是1.1,然后在axis 和 spring ws 和 cxf 之间进行选择,然后axis 可以自定义服务,然后随tomcat启动发布,sprin ...
- 5.Go-封装、继承、接口、多态和断言
面向对象 Go语言开发者认为:面向对象就是特定类型(结构体)有着自己的方法,利用这个方法完成面向对象编程, 并没有提封装.继承.多态.所以Go语言进行面向对象编程时,重点在于灵活使用方法. Go语言有 ...
- Spring入门编程问题集锦Top10
我写的一篇文章,希望对spring初学者有所帮助: 1.如何学习Spring? 你可以通过下列途径学习spring: ①. spring下载包中doc目录下的MVC-step-by-step和samp ...
- go 学习笔记之有意思的变量和不安分的常量
首先希望学习 Go 语言的爱好者至少拥有其他语言的编程经验,如果是完全零基础的小白用户,本教程可能并不适合阅读或尝试阅读看看,系列笔记的目标是站在其他语言的角度学习新的语言,理解 Go 语言,进而写出 ...
- 工作中常见的五种技术leader
力不从心型 在工作中有种技术leader,总认为自己是最好的.在方案设计的时候,自己有一种方案,下属有一种方案.leader非要别人听他的.如果两种方案没有优劣之分,比较建议的做法是让真正实施的人按照 ...
- webgl(three.js)实现室内定位,楼宇bim、实时定位三维可视化解决方案
(写在前面,谈谈物联网展会)上次深圳会展中心举行物联网展会,到了展会一看,80%以上的物联网应用都是在搞RFID,室内定位,我一度怀疑物联网落地方案的方向局限性与市场导向,后来多方面了解才明白,展会上 ...
- java之异常详解
一.什么是异常? 异常就是有异于常态,和正常情况不一样,有错误出错.在java中,阻止当前方法或作用域正常运行的情况,称之为异常. 二.异常体系 Java把异常当作对象来处理,并定义一个基类java. ...
- 理解-NumPy
# 理解 NumPy 在这篇文章中,我们将介绍使用NumPy的基础知识,NumPy是一个功能强大的Python库,允许更高级的数据操作和数学计算. # 什么是 NumPy? NumPy是一个功能强大的 ...