[CSP-S模拟测试]:string(线段树)
题目描述
给定一个由小写字母组成的字符串$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(线段树)的更多相关文章
- 【bzoj3638】Cf172 k-Maximum Subsequence Sum 模拟费用流+线段树区间合并
题目描述 给一列数,要求支持操作: 1.修改某个数的值 2.读入l,r,k,询问在[l,r]内选不相交的不超过k个子段,最大的和是多少. 输入 The first line contains inte ...
- 【8.26校内测试】【重构树求直径】【BFS模拟】【线段树维护DP】
题目性质比较显然,相同颜色联通块可以合并成一个点,重新建树后,发现相邻两个点的颜色一定是不一样的. 然后发现,对于一条链来说,每次把一个点反色,实际上使点数少了2个.如下图 而如果一条链上面有分支,也 ...
- [CSP-S模拟测试]:影魔(树状数组+线段树合并)
题目背景 影魔,奈文摩尔,据说有着一个诗人的灵魂.事实上,他吞噬的诗人灵魂早已成千上万.千百年来,他收集了各式各样的灵魂,包括诗人.牧师.帝王.乞丐.奴隶.罪人,当然,还有英雄.每一个灵魂,都有着自己 ...
- 【NOIP模拟】board(线段树维护二进制,树序号化为二进制)
题目背景 SOURCE:NOIP2016-RZZ-2 T3 题目描述 给出这样一棵“二叉树”: 每个节点有左右两个儿子,并如下定义每个节点的高度:假设父亲节点的高度为 h ,那么他的两个儿子的节点的高 ...
- BZOJ2040[2009国家集训队]拯救Protoss的故乡——模拟费用流+线段树+树链剖分
题目描述 在星历2012年,星灵英雄Zeratul预测到他所在的Aiur行星在M天后会发生持续性暴雨灾害,尤其是他们的首都.而Zeratul作为星灵族的英雄,当然是要尽自己最大的努力帮助星灵族渡过这场 ...
- 2018.10.20 NOIP模拟 蛋糕(线段树+贪心/lis)
传送门 听说是最长反链衍生出的对偶定理就能秒了. 本蒟蒻直接用线段树模拟维护的. 对于第一维排序. 维护第二维的偏序关系可以借助线段树/树状数组维护逆序对的思想建立权值线段树贪心求解. 代码
- 2018.06.29 NOIP模拟 旅馆(线段树)
旅馆 [问题描述] OIEROIEROIER 们最近的旅游计划,是到长春净月潭,享受那里的湖光山色,以及明 媚的阳光.你作为整个旅游的策划者和负责人,选择在潭边的一家著名的旅馆住 宿.这个巨大的旅馆一 ...
- 2018.06.29 NOIP模拟 排列(线段树)
排列(premu.cpp) [题目描述] 对于一个 1 到 n 的排列,逆序数的定义为:排列中第 i 位 ai的逆序数就是 a1-ai-1中比 ai大的数的个数.另外用 pi表示 a1,-,ai的逆序 ...
- 考试题string——线段树。
string[题目描述]给定一个由小写字母组成的字符串 s.有 m 次操作,每次操作给定 3 个参数 l,r,x.如果 x=1,将 s[l]~s[r]升序排序;如果 x=0,将 s[l]~s[r]降序 ...
随机推荐
- linux 正则表达式 目录
linux 通配符与正则表达式 linux 通配符 linux 正则表达式 使用grep命令 linux 扩展正则表达式 egrep linux 正则表达式 元字符
- Python 入门之编码
Python 入门之编码 1.编码初识: (1)ASCII码 :256 个 英文1个字节,不支持中文 (2)GBK(国标) : 英文1个字节 中文两个字节 (3)unicode (万国码):英文4个字 ...
- Enlarge GCD(素数筛)
题意 删去最少的数,使gcd变大 题解 只要保留相同素数因子最多的数即可. 素数筛. C++代码 #include<bits/stdc++.h> using namespace std; ...
- Client does not support authentication protocol requested by server; consider upgrading MySQL client
出现错误 Client does not support authentication protocol requested by server; consider upgrading MySQL c ...
- Chrome开发者工具详解(五)之Network面板
Chrome开发者工具面板 面板上包含了Elements面板.Console面板.Sources面板.Network面板. Timeline面板.Profiles面板.Application面板.Se ...
- oracle数据库中的存储函数
oracle中的存储函数,和系统内的函数类似,可以像调用系统函数一样调用存储函数.它与存储过程的唯一区别就是存储过程没有return返回值,存储函数可以与存储过程互换,存储函数可以在存储过程中调用. ...
- Django之modles 多对多创建第三张表
一.第一种:纯自动创建第三张表 纯自动 class Book(models.Model): title = models.CharField(max_length=32) price = models ...
- SVN本地搭建服务
本地搭建svn 服务端并使用 1.下载SVN服务端软 VisualSVN server 地址:http://subversion.apache.org/packages.html 2.安装 Visu ...
- 如何算gama(1/2)=sqrt(pi)?
关键是算e^{-x^2}在0到oo的定积分是sqrt(pi)/2. 或者利用高斯密度函数来求解
- JS深度比较两个对象是否相等
/** * 深度比较两个对象是否相等 * @type {{compare: compareObj.compare, isObject: (function(*=): boolean), isArray ...