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,每次可以交换两个相邻的元素,执行最小次数的交换移动 ...
随机推荐
- codeforces 213div(2) 365 A.Good Number 365 B.The Fibonacci Segment
#include <stdio.h> #include <string.h> bool vis[11]; int n, k; bool judge(int x) { memse ...
- 腾讯位置服务API快速入门
前言 之前项目有个需求,在网页上显示微信发送过来的位置信息,该开始想用百度地图,后来发现腾讯地图相对简单一点 快速入门 申请Key https://lbs.qq.com/guides/startup. ...
- 夯实Java基础(四)——面向对象之多态
1.多态介绍 面向对象三大特征:封装.继承.多态.多态是Java面向对象最核心,最难以理解的内容.从一定角度来看,封装和继承几乎都是为多态而准备的. 多态就是指程序中定义的引用变量所指向的具体类型和通 ...
- Java——集合类
1.容器的打印 import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import jav ...
- 给debian的docker容器添加crontab定时任务
现在大部分的docke镜像是基于debian # cat /etc/issue Debian GNU/Linux 9 \n \l Docker容器是不支持后台服务的,像systemctl servic ...
- 配置Windows Server 2008环境
上一章已经把Windows Server2008操作系统安装完毕,接下来配置一下Windows Server环境.配置网络和共享中心.配置桌面环境.配置用户IE设置.安装Telnet远程工具.配置文件 ...
- 安装Windows Server 2008
下面介绍一下,Windows Server操作系统安装,以及在企业中的应用,在小型企业中可以使用不同的版本搭建不同类型的服务,小型企业中可以搭建Web服务,FTP服务,以及DNS和DHCP服务等,在大 ...
- 三步理解--门控循环单元(GRU),TensorFlow实现
1. 什么是GRU 在循环神经⽹络中的梯度计算⽅法中,我们发现,当时间步数较⼤或者时间步较小时,循环神经⽹络的梯度较容易出现衰减或爆炸.虽然裁剪梯度可以应对梯度爆炸,但⽆法解决梯度衰减的问题.通常由于 ...
- C语言连接mysql,用GCC编译
1. main.c文件内容如下 #include <stdlib.h>#include <stdio.h>#include <winsock.h>#include ...
- 多线程编程-synchronized
使用取钱的demo来模拟实现线程的同步 package com.iotec.synchronizedTest; import java.io.ObjectInputStream; public cla ...