题目描述

给定一个由小写字母组成的字符串$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. [百家号]APT组织简介2019

    5家新APT组织被披露,2019是“后起之秀”的天下? https://baijiahao.baidu.com/s?id=1621699899936470038&wfr=spider& ...

  2. 循环Gray码的生成(非递归)

    #!/usr/bin/env python #coding:utf-8 import sys def gray_code(n): if n < 1: return [] n += 1 array ...

  3. Eclipse连接SQL Server 2008数据库

    一.准备材料 要能够使用数据库就要有相应的JDBC,所以我们要去Microsoft官网下载 https://www.microsoft.com/zh-cn/download/details.aspx? ...

  4. 【6.10校内test】T2 医院设置

    医院设置[题目链接] 感觉我超废 我是一个连floyd都不会写了的灵魂OI选手qwq(考场上写了半天spfa然后写炸了(微笑)) floyd的暴力: 1.先建树:用邻接矩阵存.存之前记得先初始化为IN ...

  5. Qt 遍历不规则树的节点

    在使用Qt的GraphicsScene作图时,遇到类似这样的需求:在scene中创建节点类似下图, 现在我要把每个节点的txt保存到xml文件中,结构为 <?xml version='1.0' ...

  6. AutoTikv简介

    AutoTikv是一个用于对TiKV数据库进行自动调优的工具.它的设计灵感来自于SIGMOD 2017的一篇paper:Automatic Database Management System Tun ...

  7. 关于JSON.parse(JSON.stringify(obj))实现深拷贝应该注意的坑

    JSON.parse(JSON.stringify(obj))我们一般用来深拷贝,其过程说白了 就是利用JSON.stringify 将js对象序列化(JSON字符串),再使用JSON.parse来反 ...

  8. egretios包接微信/facebook登录

    ios包有了,现在需要登录,就先使用微信登录吧,后继加一个facebook登录. 根据我的理解,先预测一下应该是怎么回事吧. 首先应该是要去微信的公共平台注册一下,说我的应用是什么应用,要填写企业信息 ...

  9. Spring基础09——Bean的自动装配

    1.XML配置的Bean自动装配 SpringIOC容器可以自动装配Bean,需要做的仅仅是在<bean>的autowire属性里指定自动装配的模式,而不需要手工去指定要装配的Bean,a ...

  10. 对于springmvc 很奇妙的报404错误的记录

    @RequestMapping("/editItems") public ModelAndView editItems(Integer id) throws Exception { ...