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)\)的棋盘,每个格子有一个 ...
随机推荐
- python:单例模式--使用__new__(cls)实现
单例模式:即一个类有且仅有一个实例. 那么通过python怎么实现一个类只能有一个实例呢. class Earth: """ 假如你是神,你可以创造地球 "&q ...
- C/C++ 面试-内存对齐 即不同数据类型存储空间
下面列举了Dev-C++下基本类型所占位数和取值范围: 基本型 所占位数 取值范围 输入符举例 ...
- 在ensp上的进行的浮动路由
原理 实验模拟内容 搭建实验拓扑 相关参数 其他设置端口ip都一样,serial也一样(三个路由器都要设置的) 简单测试一下连通性 下面我们分别在路由器上配置所在网段的静态路由 配置完之后我们来查看一 ...
- Visual Studio特性学习
官方档案: https://docs.microsoft.com/en-us/visualstudio/get-started/visual-studio-ide?view=vs-2019
- #redis 安装命令
redis 安装命令 cd /usr/local sudo wget http://download.redis.io/releases/redis-4.0.11.tar.gz sudo tar xf ...
- Django模型层之单表操作
Django模型层之单表操作 一 .ORM简介 我们在使用Django框架开发web应用的过程中,不可避免地会涉及到数据的管理操作(如增.删.改.查),而一旦谈到数据的管理操作,就需要用到数据库管理软 ...
- WITH AS学习
一.WITH AS的含义 WITH AS短语,也叫做子查询部分(subquery factoring),可以让你做很多事情,定义一个SQL片断,该SQL片断会被整个SQL语句所用到.有的时候, ...
- Hadoop2.8.4集群配置
建hadoop用户 #添加用户hadoop adduser hadoop 这个过程中需要输入密码两次 Enter new password: Retype new password: passwd: ...
- App开放接口API安全性之Token签名Sign的设计与实现
前言 在app开放接口api的设计中,避免不了的就是安全性问题,因为大多数接口涉及到用户的个人信息以及一些敏感的数据,所以对这些接口需要进行身份的认证,那么这就需要用户提供一些信息,比如用户名密码等, ...
- 解决Windows10关闭UAC后,开机启动项不生效的问题
Windows10关闭UAC后,会发现启动项不生效. 运行输入gpedit.msc打开组策略(家庭版没有组策略功能) 依次展开计算机配置->Windows设置->安全设置->本地策略 ...