博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
计数排序 + 线段树优化 --- Codeforces 558E : A Simple Task
阅读量:6598 次
发布时间:2019-06-24

本文共 3171 字,大约阅读时间需要 10 分钟。

 E. A Simple Task

Problem's Link:


 

Mean: 

给定一个字符串,有q次操作,每次操作将(l,r)内的字符升序或降序排列,输出q次操作后的字符串。

analyse:

基本思想是。

所谓计数排序,是对一个元素分布较集中的数字集群进行排序的算法,时间复杂度为O(n),但使用条件很苛刻。首先对n个数扫一遍,映射出每个数字出现的次数,然后再O(n)扫一遍处理出:对于数字ai,有多少个数字在ai前面。有了这个信息,我们就可以在O(1)的时间内确定出排序后ai所在的位置。

解题思路:

对于每个Query,我们先统计出(l,r)区间内每个字母出现的次数,然后分类来排序(非升或非降)。这个更新操作就相当于:

 

for(int j=x; j<=y; j++)      cnt[s[j] - 'a']++;ind = 0;for(int j=x; j<=y; j++){      while(cnt[ind] == 0)            ind++;      s[j] = ind + 'a';      cnt[ind]--;}

 

但是每次这样去统计时间复杂度是O(n),对于(10^5)*(5*10^4)的时间复杂度势必超时。所以我们需要一种在区间更新和统计上时间复杂度都客观的数据结构---线段树。

我们开26棵线段树,第i棵线段树维护的是:26个字母中排第i个的字母在各个区间的数目。

这样一来,我们就可以将一个字符串S完美的融入到这26棵线段树中去,更新和查找都从上面的O(n)变为了O(logn)。其中传递更新需要用Lazy标记。

 

Time complexity: O(q*logn*sz)

 

Source code: 

/** this code is made by crazyacking* Verdict: Accepted* Submission Date: 2015-07-15-21.40* Time: 0MS* Memory: 137KB*/#include 
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define LL long long#define ULL unsigned long longusing namespace std;#define MX 100007#define lft (idx<<1)#define rgt (lft|1)#define mid ((l+r)>>1)#define rep(i,x,y) for(int i=x;i<=y;++i)int Tree[27][4*MX];int Lazy[27][4*MX];char s[MX];void Build(int idx,int l,int r){ if(l == r) { int id = s[l]-'a'+1; Tree[id][idx] = 1; return; } Build(lft,l,mid); Build(rgt,mid+1,r); rep(i,1,26) Tree[i][idx] = Tree[i][lft] + Tree[i][rgt]; //回溯pushup}void Pushup(int id,int idx,int l,int r,int v){ Lazy[id][idx] = v; Tree[id][idx] = (r-l+1)*(v%2);}void Update(int id,int idx,int l,int r,int s,int e,int v){ if(l==s && r==e) { Pushup(id,idx,l,r,v); return; } if(Lazy[id][idx]) { Pushup(id,lft,l,mid,Lazy[id][idx]); Pushup(id,rgt,mid+1,r,Lazy[id][idx]); Lazy[id][idx] = 0; } if(e <= mid) { Update(id,lft,l,mid,s,e,v); } else if(s > mid) { Update(id,rgt,mid+1,r,s,e,v); } else { Update(id,lft,l,mid,s,mid,v), Update(id,rgt,mid+1,r,mid+1,e,v); } Tree[id][idx] = Tree[id][lft] + Tree[id][rgt];}int Query(int id,int idx,int l,int r,int s,int e) //查询s~e这段上有多少个字母i{ if(l == s && r == e) { return Tree[id][idx]; } if(Lazy[id][idx]) { Pushup(id,lft,l,mid,Lazy[id][idx]); Pushup(id,rgt,mid+1,r,Lazy[id][idx]); Lazy[id][idx] = 0; } if(e <= mid) { return Query(id,lft,l,mid,s,e); } else if(s > mid) { return Query(id,rgt,mid+1,r,s,e); } else { return Query(id,lft,l,mid,s,mid) + Query(id,rgt,mid+1,r,mid+1,e); }}int main(){ int n,m; scanf("%d %d",&n,&m); scanf("%s",s+1); Build(1,1,n); while(m--) { int s,e,k; scanf("%d %d %d",&s,&e,&k); int cnt[27] = { 0}; rep(i,1,26) { cnt[i] = Query(i,1,1,n,s,e); Update(i,1,1,n,s,e,2); } if(k)/**< non-decreasing */ { int l = s; rep(i,1,26) { int st = l; int ed = st+cnt[i]-1; if(st <= ed) { Update(i,1,1,n,st,ed,1); } //将字符串的st到ed置为i l = ed+1; } } else/**< non-increasing */ { int l = s; for(int i=26; i>=1; --i) { int st = l; int ed = st+cnt[i]-1; if(st <= ed) { Update(i,1,1,n,st,ed,1); } l = ed+1; } } } rep(i,1,n) { rep(j,1,26) { int qq = Query(j,1,1,n,i,i); if(qq) {putchar('a'+j-1); break;} } } puts(""); return 0;}

 

转载于:https://www.cnblogs.com/crazyacking/p/4649878.html

你可能感兴趣的文章
IBM预通过R语言扩展 简化Watson系统的应用
查看>>
NVIDIA与阿里云达成战略合作 共同拓展深度学习市场
查看>>
数据中心机房对环境的新要求
查看>>
JSP连接access数据库
查看>>
Loadrunner监控服务器资源
查看>>
Pandas:按条件进行行选择
查看>>
spring boot 自定义规则访问获取内部或者外部静态资源图片
查看>>
Object类
查看>>
Coding打坐
查看>>
springmvc + mybatis + ehcache + redis架构
查看>>
使用rollup打包库的一种基本配置
查看>>
sed指定行范围匹配(转贴!)
查看>>
JS实例(一)百度前端技术学院任务(十三)
查看>>
hdu 5009 Paint Pearls
查看>>
java使用json_java使用json
查看>>
java 数组有序_Java有序数组
查看>>
Java配置环境变量、方法和原因
查看>>
23种设计模式(3):抽象工厂模式
查看>>
防火墙导致MySQL无法访问的问题解决案例
查看>>
Jquery 选择器注意的问题--记录(五)
查看>>