题目描述

给定一个由小写字母组成的字符串$s$。

有$m$次操作,每次操作给定$3$个参数$l,r,x$。

如果$x=1$,将$s[l]~s[r]$升序排序;

如果$x=0$,将$s[l]~s[r]$降序排序。

你需要求出最终序列。


输入格式

第一行两个整数$n,m$。
第二行一个字符串$s$。
接下来m行每行三个整数$l,r,x$。


输出格式

一行一个字符串表示答案。


样例

样例输入

5 2
cabcd
1 3 1
3 5 0

样例输出

abdcc


数据范围与提示

对于$40\%$的数据,$n,m\leqslant 1,000$。
对于$100\%$的数据,$n,m\leqslant 100,000$。


题解

看到这道题,我就想到了:[BZOJ4552]:[Tjoi2016&Heoi2016]排序(桶排序)

然而,那道题我使用桶排序卡过的,时限还是$6,000ms$,所以我当场懵逼,线段树是肯定看出来了,但是不知道该怎么操作……

打题一定要打正解挖~

$40\%$算法:

直接用$sort$搞就好了,重载一下运算符,我觉得我说的每一句都是废话……

桶排一分也不能多拿(万恶的出题人)。

时间复杂度:

  $\Theta(m\times n)$(桶排序)。

  $\Theta( m\times n\log n)$(快排)。

期望得分:$40$分。

$100\%$算法:

因为这道题串中只有26个字母,所以就好说多了,用线段树维护区间内$a~z$的个数,每次修改拆成26个修改就行了。

时间复杂度:$\Theta(26\times m\times \log n)$。

期望得分:$100$分。


代码时刻

$40\%$算法:

#include<bits/stdc++.h>
using namespace std;
int n,m,l,r;
bool x;
int a[100001];
char ch[100001];
int t[50];
int st,ed;
void change1()
{
register int maxn=0,minn=20020923,lft=l;
for(int i=l;i<=r;i++)
{
t[a[i]]++;
maxn=max(maxn,a[i]);
minn=min(minn,a[i]);
}
for(register int i=minn;i<=maxn;i++)
while(t[i])
{
a[lft++]=i;
t[i]--;
}
}
void change2()
{
int maxn=0,minn=20020923,lft=l;
for(register int i=l;i<=r;i++)
{
t[a[i]]++;
maxn=max(maxn,a[i]);
minn=min(minn,a[i]);
}
for(register int i=maxn;i>=minn;i--)
while(t[i])
{
a[lft++]=i;
t[i]--;
}
} int main()
{
st=clock();
scanf("%d%d%s",&n,&m,ch+1);
for(register int i=1;i<=n;i++)
a[i]=ch[i]-'a'+1;
while(m--)
{
scanf("%d%d%d",&l,&r,&x);
if(x)change1();
else change2();
}
for(register int i=1;i<=n;i++)
printf("%c",(char)a[i]+'a'-1);
return 0;
}

$100\%$算法:

#include<bits/stdc++.h>
#define L(x) x<<1
#define R(x) x<<1|1
using namespace std;
int n,m;
char ch[100001];
int tr[400001];
int flag[30];
void pushup(int x){if(tr[L(x)]==tr[R(x)])tr[x]=tr[L(x)];}
void pushdown1(int x){if(tr[x])tr[L(x)]=tr[R(x)]=tr[x];}
void pushdown2(int x){if(tr[x])tr[L(x)]=tr[R(x)]=tr[x];tr[x]=0;}
void build(int x,int l,int r)
{
if(l==r){tr[x]=ch[l]-'a'+1;return;}
int mid=(l+r)>>1;
build(L(x),l,mid);
build(R(x),mid+1,r);
pushup(x);
}
void ask(int x,int l,int r,int L,int R)
{
if(r<L||R<l)return;
if(L<=l&&r<=R&&tr[x]){flag[tr[x]]+=r-l+1;return;}
int mid=(l+r)>>1;
pushdown1(x);
ask(L(x),l,mid,L,R);
ask(R(x),mid+1,r,L,R);
}
void change(int x,int l,int r,int L,int R,int v)
{
if(r<L||R<l)return;
if((L<=l&&r<=R)||tr[x]==v){tr[x]=v;return;}
int mid=(l+r)>>1;
pushdown2(x);
change(L(x),l,mid,L,R,v);
change(R(x),mid+1,r,L,R,v);
pushup(x);
}
void print(int x,int l,int r)
{
if(tr[x]){for(int i=l;i<=r;i++)printf("%c",(char)tr[x]+'a'-1);return;}
int mid=(l+r)>>1;
print(L(x),l,mid);
print(R(x),mid+1,r);
}
int main()
{
scanf("%d%d%s",&n,&m,ch+1);
build(1,1,n);
while(m--)
{
int l,r,x;
scanf("%d%d%d",&l,&r,&x);
memset(flag,0,sizeof(flag));
ask(1,1,n,l,r);
if(x)for(int i=1;i<=26;i++){change(1,1,n,l,l+flag[i]-1,i);l+=flag[i];}
else for(int i=26;i>=1;i--){change(1,1,n,l,l+flag[i]-1,i);l+=flag[i];}
}
print(1,1,n);
return 0;
}

rp++

[CSP-S模拟测试]:string(线段树)的更多相关文章

  1. 【bzoj3638】Cf172 k-Maximum Subsequence Sum 模拟费用流+线段树区间合并

    题目描述 给一列数,要求支持操作: 1.修改某个数的值 2.读入l,r,k,询问在[l,r]内选不相交的不超过k个子段,最大的和是多少. 输入 The first line contains inte ...

  2. 【8.26校内测试】【重构树求直径】【BFS模拟】【线段树维护DP】

    题目性质比较显然,相同颜色联通块可以合并成一个点,重新建树后,发现相邻两个点的颜色一定是不一样的. 然后发现,对于一条链来说,每次把一个点反色,实际上使点数少了2个.如下图 而如果一条链上面有分支,也 ...

  3. [CSP-S模拟测试]:影魔(树状数组+线段树合并)

    题目背景 影魔,奈文摩尔,据说有着一个诗人的灵魂.事实上,他吞噬的诗人灵魂早已成千上万.千百年来,他收集了各式各样的灵魂,包括诗人.牧师.帝王.乞丐.奴隶.罪人,当然,还有英雄.每一个灵魂,都有着自己 ...

  4. 【NOIP模拟】board(线段树维护二进制,树序号化为二进制)

    题目背景 SOURCE:NOIP2016-RZZ-2 T3 题目描述 给出这样一棵“二叉树”: 每个节点有左右两个儿子,并如下定义每个节点的高度:假设父亲节点的高度为 h ,那么他的两个儿子的节点的高 ...

  5. BZOJ2040[2009国家集训队]拯救Protoss的故乡——模拟费用流+线段树+树链剖分

    题目描述 在星历2012年,星灵英雄Zeratul预测到他所在的Aiur行星在M天后会发生持续性暴雨灾害,尤其是他们的首都.而Zeratul作为星灵族的英雄,当然是要尽自己最大的努力帮助星灵族渡过这场 ...

  6. 2018.10.20 NOIP模拟 蛋糕(线段树+贪心/lis)

    传送门 听说是最长反链衍生出的对偶定理就能秒了. 本蒟蒻直接用线段树模拟维护的. 对于第一维排序. 维护第二维的偏序关系可以借助线段树/树状数组维护逆序对的思想建立权值线段树贪心求解. 代码

  7. 2018.06.29 NOIP模拟 旅馆(线段树)

    旅馆 [问题描述] OIEROIEROIER 们最近的旅游计划,是到长春净月潭,享受那里的湖光山色,以及明 媚的阳光.你作为整个旅游的策划者和负责人,选择在潭边的一家著名的旅馆住 宿.这个巨大的旅馆一 ...

  8. 2018.06.29 NOIP模拟 排列(线段树)

    排列(premu.cpp) [题目描述] 对于一个 1 到 n 的排列,逆序数的定义为:排列中第 i 位 ai的逆序数就是 a1-ai-1中比 ai大的数的个数.另外用 pi表示 a1,-,ai的逆序 ...

  9. 考试题string——线段树。

    string[题目描述]给定一个由小写字母组成的字符串 s.有 m 次操作,每次操作给定 3 个参数 l,r,x.如果 x=1,将 s[l]~s[r]升序排序;如果 x=0,将 s[l]~s[r]降序 ...

随机推荐

  1. java8----Predicate接口的使用

    //5.lambda表达式中加入Predicate // 甚至可以用and().or()和xor()逻辑函数来合并Predicate, // 例如要找到所有以J开始,长度为四个字母的名字,你可以合并两 ...

  2. 你知道 Java 类是如何被加载的吗?

    前言 最近给一个非 Java 方向的朋友讲了下双亲委派模型,朋友让我写篇文章深度研究下JVM 的 ClassLoader,我确实也好久没写 JVM 相关的文章了,有点手痒痒,涂了皮炎平也抑制不住的那种 ...

  3. 线性表源码分享(c++),包含顺序表、单链表、循环链表、双向链表

    ---恢复内容开始--- 我是一个c++和数据结构的初学者,本文主要是把清华大学出版社的数据结构(用面向对象方法与c++语言描述)(第2版)这本书中第二章线性表的源码抄下来,在学习的过程中有助于加深印 ...

  4. GmSSL Build with VS2017

    使用背景: 最近研究GB35114, 有关于sip协议部分,exosip的已经编译过,由于gb3511中采用的是国密算法,因此这里记录一下GMSSL在windows下的编译过程以及遇到的错误 详细GM ...

  5. 关于css清除浮动

    1.overflow:hidden 较简单,兼容于市面浏览器.负面效果不详.暂不推荐使用.2.定义clear类,并把clear类赋给浮动元素的父级元素. .clear{display:block;ov ...

  6. 【FAQ】P3. 为什么 torch.cuda.is_available() 是 False

    为什么 torch.cuda.is_available() 是 False torch.cuda.is_available(),这个指令的作用是看,你电脑的 GPU 能否被 PyTorch 调用. 如 ...

  7. angularJS(一):表达式、指令

    简介 以 JavaScript 编写的库,是一个 JavaScript 框架 一.表达式 AngularJS 使用 表达式 把数据绑定到 HTML. 表达式写在双大括号内:{{ expression ...

  8. ASP.NET中数据库数据导入Excel并打印(2)

    大家可能觉得上面的代码比较复杂,因为上面对于对打印要求比较高的应用,是十分有效的.如果只是单单对数据进行导出,还可以使用简单的格式,比如使用以下的代码:      Private Sub Page_L ...

  9. 梯度下降算法(Gradient descent)GD

    1.我们之前已经定义了代价函数J,可以将代价函数J最小化的方法,梯度下降是最常用的算法,它不仅仅用在线性回归上,还被应用在机器学习的众多领域中,在后续的课程中,我们将使用梯度下降算法最小化其他函数,而 ...

  10. java中使用SimpleDateFormat实现字符串和日期的相互转换

    java中使用SimpleDateFormat实现字符串和日期的相互转换 import java.text.ParseException; import java.text.SimpleDateFor ...