Codeforces J. A Simple Task(多棵线段树)
题目描述:
Description
This task is very simple. Given a string S of length n and q queries each query is on the format i j k which means sort the substring consisting of the characters from i to j in non-decreasing order if k = 1 or in non-increasing order if k = 0.
Output the final string after applying the queries.
Input
The first line will contain two integers n, q (1 ≤ n ≤ 105, 0 ≤ q ≤ 50 000), the length of the string and the number of queries respectively.
Next line contains a string S itself. It contains only lowercase English letters.
Next q lines will contain three integers each i, j, k (1 ≤ i ≤ j ≤ n, ).
Output
Output one line, the string S after applying the queries.
Sample Input
10 5
abacdabcda
7 10 0
5 8 1
1 4 0
3 6 0
7 10 1
10 1
agjucbvdfk
1 10 1
Sample Output
cbcaaaabdd
abcdfgjkuv
思路:
题目的意思是,给定一个字符串,有q个询问,要把区间[l,r]的字符根据k的值升序(k=1),或降序(k=0)改变。
因为字母集有26个字母,就可以建立27棵线段树分别维护区间上每个字母出现的次数,一般地,第i棵线段树维护字母i-1+'a'的数目。
维护字母在区间上出现的次数有什么用?想想我们要做的事情,就是把区间[l,r]上的排一个序,字母集有限,想到计数排序,用一个27大小(0不存)的cnt数组,cnt[i]记录字母i出现的次数
如果k是1,则下标从1开始,如果对应那一项不为0,说明区间这个位置要被覆盖成i,就直接覆盖掉原来的线段树对应区间[l,r]上记录的字母i出现的次数,注意这里是直接覆盖,而不是累加,所以要修改线段树模板的区间和的upgrade函数的sum[a][r]+=改为sum[a][r]=,(a表示字母a对应的线段树)对应的懒标记也改为=。
一开始由于循环写的有点长(值代码长度),把计数的变量写叉了,有因为上面没有注意是最直接覆盖,一直出现out of bound错误,一开始还莫名其妙,搞了一个上午一直到晚上才知道写错了(╯‵□′)╯︵┻━┻,bug真好写,改是真难。
一开始写得麻烦了,比如把区间修改成字母a,然后我还在后面有把在这个区间上的,原来的对应的字母对应的线段树,一个位置一个位置的修改,然后提交,超时。。。
咋办嘞?原来只要在开始输入l,r那会统计每个字母在这个区间上出现次数后,紧接着立马删掉原来的数据(区间上的数据全置0),这么一改,好家伙,连样例都过不了了-_-||
找了半天,然后联想到这题的直接覆盖的不同寻常之处,也就是不同于区间和,才发现懒标记我标的有问题,没有懒标记我标0,懒标记为0(区间清零要用的)的还是0,那我在pushdown的时候怎么区分这两种情况呢?
咋办?标奇偶!神奇,覆盖的标记是1,清零的标记是2,没有标记的是0,这样就可以区分,那我咋使用呢?lz%2就行,1就是1,2就是0,可以正常使用了。
这题思路清晰,就是要注意细节,果然还是我太菜了。。
知识点:线段树的覆盖(自编题目)
代码:(开了氧气上瘾了)(注释依稀可见我超时的地方)
#include <iostream>
#include <cstring>
#include <memory.h>
#define max_n 100005
using namespace std;
char s[max_n];
int sum[][max_n<<];
int lz[][max_n<<];
int cnt[];
int n;
int q;
int k;
void pushup(int a,int r)
{
sum[a][r] = sum[a][r<<]+sum[a][r<<|];
}
void build(int a,int r,int lc,int rc)
{
if(lc==rc)
{
if(a==s[lc]-'a'+)
sum[a][r] = ;
lz[a][r] = ;
return;
}
int mid = (lc+rc)>>;
build(a,r<<,lc,mid);
build(a,r<<|,mid+,rc);
pushup(a,r);
}
void pushdown(int a,int r,int ln,int rn)
{
if(lz[a][r])
{
//cout << "r" << r << endl;
sum[a][r<<] = ln*(lz[a][r]%);//注意这里的改变
sum[a][r<<|] = rn*(lz[a][r]%);//还有这里
lz[a][r<<] = lz[a][r];
lz[a][r<<|] = lz[a][r];
lz[a][r] = ;
}
}
void upgrade(int a,int r,int L,int R,int lc,int rc,int val)
{
if(L<=lc&&rc<=R)
{
sum[a][r] = (rc-lc+)*(val%);//这里,这里!
lz[a][r] = val;//直接覆盖就是等于哦
return;
}
int mid = (lc+rc)>>;
pushdown(a,r,mid-lc+,rc-mid);
if(L<=mid) upgrade(a,r<<,L,R,lc,mid,val);
if(mid<R) upgrade(a,r<<|,L,R,mid+,rc,val);
pushup(a,r);
}
int query(int a,int r,int L,int R,int lc,int rc)
{
if(L<=lc&&rc<=R)
{
return sum[a][r];
}
int mid = (lc+rc)>>;
pushdown(a,r,mid-lc+,rc-mid);
int res = ;
if(L<=mid) res += query(a,r<<,L,R,lc,mid);
if(mid<R) res += query(a,r<<|,L,R,mid+,rc);
return res;
}
#pragma optimize(2)
int main()
{
cin >> n >> q;
for(int i = ;i<=n;i++)
{
cin >> s[i];
}
for(int i = ;i<=;i++)
{
build(i,,,n);
}
int l,r,k;
for(int i=;i<q;i++)
{
cin >> l >> r >> k;
for(int j = ;j<=;j++)
{
cnt[j] = query(j,,l,r,,n);
upgrade(j,,l,r,,n,);//直接清零
}
if(k==)
{
int lp = l;
for(int p = ; p<=; p++)
{
if(cnt[p])
{
char ch =p+'a'-;
//cout << ch << ":" << cnt[p] << endl;
upgrade(p,,lp,lp+cnt[p]-,,n,);
lp = lp+cnt[p];
/*for(int j = 0; j<cnt[p];j++)
{
upgrade(s[lp]-'a'+1,1,lp,lp,1,n,-1);
s[lp]=p+'a'-1;
lp++;
}*/
}
}
/*for(int i = 1; i<=n; i++)
{
cout << s[i];
}
cout << endl;*/
}
else
{
int lp = l;
for(int p = ; p>=; p--)
{
if(cnt[p])
{
char ch = p+'a'-;
//cout << ch << ":" << cnt[p] << endl;
upgrade(p,,lp,lp+cnt[p]-,,n,);
lp = lp+cnt[p];
/*for(int j = 0; j<cnt[p];j++)
{
upgrade(s[lp]-'a'+1,1,lp,lp,1,n,-1);
s[lp] = p+'a'-1;
lp++;
}*/ }
}
/*for(int i = 1; i<=n; i++)
{
cout << s[i];
}
cout << endl;*/
}
}
for(int i = ;i<=n;i++)
{
for(int j = ;j<;j++)
{
cnt[j] = query(j,,i,i,,n);
if(cnt[j])
{
char ch = j-+'a';
cout << ch;
}
}
}
cout << endl;
return ;
}
Codeforces J. A Simple Task(多棵线段树)的更多相关文章
- Codeforces 558E A Simple Task (计数排序&&线段树优化)
题目链接:http://codeforces.com/contest/558/problem/E E. A Simple Task time limit per test5 seconds memor ...
- 计数排序 + 线段树优化 --- Codeforces 558E : A Simple Task
E. A Simple Task Problem's Link: http://codeforces.com/problemset/problem/558/E Mean: 给定一个字符串,有q次操作, ...
- CodeForces 588E A Simple Task(线段树)
This task is very simple. Given a string S of length n and q queries each query is on the format i j ...
- Codeforces 588E. A Simple Task (线段树+计数排序思想)
题目链接:http://codeforces.com/contest/558/problem/E 题意:有一串字符串,有两个操作:1操作是将l到r的字符串升序排序,0操作是降序排序. 题解:建立26棵 ...
- Codeforces 558E A Simple Task(计数排序+线段树优化)
http://codeforces.com/problemset/problem/558/E Examples input 1 abacdabcda output 1 cbcaaaabdd input ...
- codeforces 558E A Simple Task 线段树
题目链接 题意较为简单. 思路: 由于仅仅有26个字母,所以用26棵线段树维护就好了,比較easy. #include <iostream> #include <string> ...
- CodeForces - 960F Pathwalks —— 主席树(n棵线段树)
题目链接:https://vjudge.net/problem/CodeForces-960F You are given a directed graph with n nodes and m ed ...
- Codeforces 1175F - The Number of Subpermutations(线段树+单调栈+双针/分治+启发式优化)
Codeforces 题面传送门 & 洛谷题面传送门 由于这场的 G 是道毒瘤题,蒟蒻切不动就只好来把这场的 F 水掉了 看到这样的设问没人想到这道题吗?那我就来发篇线段树+单调栈的做法. 首 ...
- codeforces 811E Vladik and Entertaining Flags(线段树+并查集)
codeforces 811E Vladik and Entertaining Flags 题面 \(n*m(1<=n<=10, 1<=m<=1e5)\)的棋盘,每个格子有一个 ...
随机推荐
- ssh登录服务器提示错误no hostkey alg
ssh登录服务器提示错误no hostkey alg ssh root@192.168.1.100 -vvv 提示失败: no hostkey alg 登录到192.168.1.100服务器 rm - ...
- PCL贪婪投影三角化算法
贪婪投影三角化算法是一种对原始点云进行快速三角化的算法,该算法假设曲面光滑,点云密度变化均匀,不能在三角化的同时对曲面进行平滑和孔洞修复. 方法: (1)将三维点通过法线投影到某一平面 (2)对投影得 ...
- jmeter3.1连接数据库报错,ORA-00923: 未找到要求的 FROM 关键字
Jmeter不仅仅可以测试接口,还可以对数据库进行压力测试.或者造数据. 准备工作:待测试数据库地址.用户名及其密码.Oracle驱动ojdbc14.jar 一.将ojdbc14.jar放至Jmete ...
- 【LeetCode】最接近的三数之和【排序,固定k1,二分寻找k2和k3】
给定一个包括 n 个整数的数组 nums 和 一个目标值 target.找出 nums 中的三个整数,使得它们的和与 target 最接近.返回这三个数的和.假定每组输入只存在唯一答案. 例如,给定数 ...
- 09 Servlet相关知识点---学习笔记
1.概念:运行在服务器端的小程序 Servlet就是一个接口,定义了Java类被浏览器访问到(tomcat识别)的规则.将来我们自定义一个类,实现Servlet接口,复写方法. 2.快速入门:(1)创 ...
- Java开发笔记(一百二十二)AWT选择框
前面介绍了两种文本输入框的用法,不过实际应用很少需要用户亲自文字,而是在界面上列出几个选项,让用户勾勾点点完成选择,这样既方便也不容易弄错.依据选择的唯一性,可将选项控件分为两类:一类是在方框中打勾的 ...
- 为什么Redis单线程却能支撑高并发?
作者:Draveness 原文链接:draveness.me/redis-io-multiplexing 最近在看 UNIX 网络编程并研究了一下 Redis 的实现,感觉 Redis 的源代码十分适 ...
- python3.7 pip升级或安装,拒绝访问 解决方案
- day31——recv工作原理、高大上版解决粘包方式、基于UDP协议的socket通信
day31 recv工作原理 源码解释: Receive up to buffersize bytes from the socket. 接收来自socket缓冲区的字节数据, For the opt ...
- AS3放大镜工具类
package { import flash.display.Bitmap; import flash.display.BitmapData; import flash.display.Display ...