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

本文共 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

你可能感兴趣的文章
【Java】native关键字
查看>>
HTML基础知识 table中 th,td,tr
查看>>
SQLite datatype
查看>>
续Gulp使用入门编译Sass
查看>>
分布式中Redis实现Session终结篇
查看>>
access调用联系
查看>>
基础公共样式设置
查看>>
iview给radio按钮组件加点击事件
查看>>
Charles 使用
查看>>
new/delete 和malloc/free 的区别(综合转帖)
查看>>
(并查集)小希的迷宫 --HDU -- 1272
查看>>
浅谈php中使用websocket
查看>>
MongoDB下,启动服务
查看>>
sql 表连接
查看>>
上传插件(WebUploader)
查看>>
粒子效果 CCParticleSystem 编码的实现
查看>>
Objective-C中的一些特殊的数据类型
查看>>
https原理
查看>>
IOS学习笔记--IOS常用控件汇总
查看>>
设置h5页面不可复制文字
查看>>