非常好的一道题,是线段树的常见玩法

将字符串转化为1~26个数

对区间开一棵线段树,用两个数组分别维护区间中1~26每个数的个数以及一个区间覆盖标记,表示这个区间是否被某一个值覆盖了

在每次排序时,首先查出这个区间中1~26每个数出现的次数,然后因为是排过序的,所以相等的数排完序之后一定是连续的一段区间,这样如果升序,我们就对整个区间从小到大进行覆盖,否则从大到小覆盖

最后遍历整棵线段树输出即可

一句话总结:每次排序只需做一次区间查询,26次区间覆盖,这样时间复杂度O(26nlogn)

#include <cstdio>
#include <cmath>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#include <queue>
#include <stack>
#define ls tree[rt].lson
#define rs tree[rt].rson
#define rt1 rt<<1
#define rt2 (rt<<1)|1
using namespace std;
struct Tree
{
bool tag[30];
int s[30];
int lson;
int rson;
}tree[400005];
struct node
{
int v[30];
}zero;
int n,q;
int a[100005];
char s[100005];
void pushdown(int rt)
{
if(ls==rs)
{
return;
}
for(int i=1;i<=26;i++)
{
if(tree[rt].tag[i])
{
for(int j=1;j<=26;j++)
{
tree[rt1].tag[j]=0;
tree[rt1].s[j]=0;
tree[rt2].tag[j]=0;
tree[rt2].s[j]=0;
}
tree[rt1].tag[i]=1;
tree[rt2].tag[i]=1;
tree[rt1].s[i]=tree[rt1].rson-tree[rt1].lson+1;
tree[rt2].s[i]=tree[rt2].rson-tree[rt2].lson+1;
tree[rt].tag[i]=0;
break;
}
}
}
void buildtree(int rt,int l,int r)
{
tree[rt].lson=l;
tree[rt].rson=r;
if(l==r)
{
tree[rt].s[a[l]]=1;
return;
}
int mid=(l+r)>>1;
buildtree(rt1,l,mid);
buildtree(rt2,mid+1,r);
for(int i=1;i<=26;i++)
{
tree[rt].s[i]=tree[rt1].s[i]+tree[rt2].s[i];
}
}
node add(node x,node y)
{
node ret=zero;
for(int i=1;i<=26;i++)
{
ret.v[i]=x.v[i]+y.v[i];
}
return ret;
}
node query(int rt,int l,int r)
{
if(ls>r||rs<l)
{
return zero;
}else if(ls>=l&&rs<=r)
{
node ret=zero;
for(int i=1;i<=26;i++)
{
ret.v[i]=tree[rt].s[i];
}
return ret;
}
pushdown(rt);
int mid=(ls+rs)>>1;
return add(query(rt1,l,r),query(rt2,l,r));
}
void update(int rt,int l,int r,int val)
{
if(ls>r||rs<l)
{
return;
}
if(ls>=l&&rs<=r)
{
for(int i=1;i<=26;i++)
{
tree[rt].s[i]=0;
tree[rt].tag[i]=0;
}
tree[rt].tag[val]=1;
tree[rt].s[val]=rs-ls+1;
return;
}
pushdown(rt);
int mid=(ls+rs)>>1;
if(l<=mid)
{
update(rt1,l,r,val);
}
if(r>mid)
{
update(rt2,l,r,val);
}
for(int i=1;i<=26;i++)
{
tree[rt].s[i]=tree[rt1].s[i]+tree[rt2].s[i];
}
}
void pushit(int rt)
{
pushdown(rt);
if(ls==rs)
{
return;
}
pushit(rt1);
pushit(rt2);
}
void print(int rt)
{
if(ls==rs)
{
for(int i=1;i<=26;i++)
{
if(tree[rt].s[i])
{
printf("%c",i-1+'a');
return;
}
}
}
print(rt1);
print(rt2);
}
inline int read()
{
int f=1,x=0;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
int main()
{
// freopen("third.in","r",stdin);
// freopen("third.out","w",stdout);
n=read(),q=read();
scanf("%s",s+1);
for(int i=1;i<=n;i++)
{
a[i]=s[i]-'a'+1;
}
buildtree(1,1,n);
for(int i=1;i<=q;i++)
{
int l=read(),r=read(),typ=read();
node temp=query(1,l,r);
if(typ==1)
{
for(int j=1;j<=26;j++)
{
update(1,l,l+temp.v[j]-1,j);
l+=temp.v[j];
}
}else
{
for(int j=26;j>=1;j--)
{
update(1,l,l+temp.v[j]-1,j);
l+=temp.v[j];
}
}
}
pushit(1);
print(1);
printf("\n");
return 0;
}

CF558E的更多相关文章

  1. CF558E A Simple Task

    题目大意: 给定一个长度不超过10^5的字符串(小写英文字母),和不超过5000个操作. 每个操作 L R K 表示给区间[L,R]的字符串排序,K=1为升序,K=0为降序. 最后输出最终的字符串 首 ...

  2. 【CF558E】 A Simple Task (权值线段树)

    题目链接 用权值线段树维护每个字母在\([l,r]\)出现的次数,每次修改把每个字母在区间的出现次数记下来,然后清空这段区间,再按顺序插进去就好了. 时间复杂度\(O(n\log n*26)\) (好 ...

  3. CF558E A simple task 线段树

    这道题好猥琐啊啊啊啊啊啊 写了一个上午啊啊啊啊 没有在update里写pushup啊啊啊啊 题目大意: 给你一个字符串s,有q个操作 l r 1 :把sl..rsl..r按升序排序 l r 0 :把s ...

  4. CF-558E (线段树/分块)

    解题思路: 很显然突破口就是字符集比较小,分块和线段树都能A 话说线段树时间是分块5倍啊 代码(线段树): #include<cstdio> #include<cstring> ...

随机推荐

  1. mysql 原理 ~ 索引通说

    简介: 来说说索引吧目的:为了加快数据库的数据查找速度,索引应用而生基础知识基本定义  1 遍历 所谓遍历二叉树,就是按一定的规则和顺序走遍二叉树的所有结点,使每一个结点都被访问一次,而且只被访问一次 ...

  2. 7.4mybatis整合ehcache(mybatis无法实现分布式缓存必须和其他缓存框架整合)

    <\mybatis\day02\14查询缓存-二级缓存-整合ehcache.av> mybatis的缓存机制(一级缓存二级缓存和刷新缓存)和mybatis整合ehcache-- 这里有做本 ...

  3. python selenium+phantomJS自动化测试环境

    0x00配置phantomJS 1. 在windows平台下 此种方法是弹浏览器进行自动化测试的. 1.下载谷歌的驱动 https://chromedriver.storage.googleapis. ...

  4. mybatis 三剑客 generator配置 、mybatis plugin

    generator配置 1.配置pom.xml 导入mysql驱动.mybatis.mybatis-generator的依赖 <dependency> <groupId>org ...

  5. OGG初始加载过程概述

    您可以使用Oracle GoldenGate来: 执行独立的批量加载以填充数据库表以进行迁移或其他用途. 将数据作为初始同步运行的一部分加载到数据库表中,以准备与Oracle GoldenGate进行 ...

  6. mysql进制之间的转换

    1.十进制转换成二进制 select bin(5); 2.十进制转换成八进制 select oct(5); 3.十进制转换成十六进制 select hex(5); 4.二进制转换成十进制 select ...

  7. 工作流程引挈 https://www.flowable.org/

    工作流程引挈 :   https://www.flowable.org/ 起源:JBPM,Activiti

  8. Json的序列化与反序列化以及乱入的k_BackingField

    0.Newtonsoft.json 最简单的最强大的基于c#的json解析库是Newtonsoft.json 在NuGet程序包管理器中在线搜索“json”,选择JSon.Net,并安装.   使用到 ...

  9. css3 - 旋转的木马

    参考资料: 张鑫旭  : http://www.zhangxinxu.com/wordpress/2012/09/css3-3d-transform-perspective-animate-trans ...

  10. ansible笔记(7):常用模块之系统类模块

    ansible笔记():常用模块之系统类模块 cron模块 cron模块可以帮助我们管理远程主机中的计划任务,功能相当于crontab命令. 在了解cron模块的参数之前,先写出一些计划任务的示例,示 ...