计数排序 + 线段树优化 --- Codeforces 558E : A Simple Task
E. A Simple Task
Problem's Link: http://codeforces.com/problemset/problem/558/E
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 = ;
- for(int j=x; j<=y; j++)
- {
- while(cnt[ind] == )
- 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 <queue>
- #include <cstdio>
- #include <set>
- #include <string>
- #include <stack>
- #include <cmath>
- #include <climits>
- #include <map>
- #include <cstdlib>
- #include <iostream>
- #include <vector>
- #include <algorithm>
- #include <cstring>
- #define LL long long
- #define ULL unsigned long long
- using 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[][*MX];
- int Lazy[][*MX];
- char s[MX];
- void Build(int idx,int l,int r)
- {
- if(l == r)
- {
- int id = s[l]-'a'+;
- Tree[id][idx] = ;
- return;
- }
- Build(lft,l,mid);
- Build(rgt,mid+,r);
- rep(i,,) 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+)*(v%);
- }
- 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+,r,Lazy[id][idx]);
- Lazy[id][idx] = ;
- }
- if(e <= mid) { Update(id,lft,l,mid,s,e,v); }
- else if(s > mid) { Update(id,rgt,mid+,r,s,e,v); }
- else { Update(id,lft,l,mid,s,mid,v), Update(id,rgt,mid+,r,mid+,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+,r,Lazy[id][idx]);
- Lazy[id][idx] = ;
- }
- if(e <= mid) { return Query(id,lft,l,mid,s,e); }
- else if(s > mid) { return Query(id,rgt,mid+,r,s,e); }
- else { return Query(id,lft,l,mid,s,mid) + Query(id,rgt,mid+,r,mid+,e); }
- }
- int main()
- {
- int n,m;
- scanf("%d %d",&n,&m);
- scanf("%s",s+);
- Build(,,n);
- while(m--)
- {
- int s,e,k;
- scanf("%d %d %d",&s,&e,&k);
- int cnt[] = {};
- rep(i,,)
- {
- cnt[i] = Query(i,,,n,s,e);
- Update(i,,,n,s,e,);
- }
- if(k)/**< non-decreasing */
- {
- int l = s;
- rep(i,,)
- {
- int st = l;
- int ed = st+cnt[i]-;
- if(st <= ed) { Update(i,,,n,st,ed,); } //将字符串的st到ed置为i
- l = ed+;
- }
- }
- else/**< non-increasing */
- {
- int l = s;
- for(int i=; i>=; --i)
- {
- int st = l;
- int ed = st+cnt[i]-;
- if(st <= ed) { Update(i,,,n,st,ed,); }
- l = ed+;
- }
- }
- }
- rep(i,,n)
- {
- rep(j,,)
- {
- int qq = Query(j,,,n,i,i);
- if(qq) {putchar('a'+j-); break;}
- }
- }
- puts("");
- return ;
- }
计数排序 + 线段树优化 --- Codeforces 558E : A Simple Task的更多相关文章
- CodeForces 558E(计数排序+线段树优化)
题意:一个长度为n的字符串(只包含26个小字母)有q次操作 对于每次操作 给一个区间 和k k为1把该区间的字符不降序排序 k为0把该区间的字符不升序排序 求q次操作后所得字符串 思路: 该题数据规模 ...
- Codeforces 558E A Simple Task (计数排序&&线段树优化)
题目链接:http://codeforces.com/contest/558/problem/E E. A Simple Task time limit per test5 seconds memor ...
- Codeforces 558E A Simple Task(计数排序+线段树优化)
http://codeforces.com/problemset/problem/558/E Examples input 1 abacdabcda output 1 cbcaaaabdd input ...
- Nowcoder Hash Function ( 拓扑排序 && 线段树优化建图 )
题目链接 题意 : 给出一个哈希表.其避免冲突的方法是线性探测再散列.现在问你给出的哈希表是否合法.如果合法则输出所有元素插入的顺序.如果有多解则输出字典序最小的那一个.如果不合法则输出 -1 分析 ...
- Codeforces 558E A Simple Task(权值线段树)
题目链接 A Simple Task 题意 给出一个小写字母序列和若干操作.每个操作为对给定区间进行升序排序或降序排序. 考虑权值线段树. 建立26棵权值线段树.每次操作的时候先把26棵线段树上的 ...
- codeforces 558E A Simple Task 线段树
题目链接 题意较为简单. 思路: 由于仅仅有26个字母,所以用26棵线段树维护就好了,比較easy. #include <iostream> #include <string> ...
- Codeforces 558E A Simple Task
题意:给定一个字符串,以及m次操作,每次操作对字符串的一个子区间进行升序或降序排序,求m次操作后的串 考虑桶排,发现线段树可以模拟桶排的过程,所以对26个字母分别建立线段树即可 #include< ...
- Educational Codeforces Round 69 E - Culture Code (最短路计数+线段树优化建图)
题意:有n个空心物品,每个物品有外部体积outi和内部体积ini,如果ini>outj,那么j就可以套在i里面.现在我们要选出n个物品的一个子集,这个子集内的k个物品全部套在一起,且剩下的物品都 ...
- [Codeforces 1197E]Culture Code(线段树优化建图+DAG上最短路)
[Codeforces 1197E]Culture Code(线段树优化建图+DAG上最短路) 题面 有n个空心物品,每个物品有外部体积\(out_i\)和内部体积\(in_i\),如果\(in_i& ...
随机推荐
- [Aaronyang] 写给自己的WPF4.5 笔记23 [3d交互与动画 4/4]
效果图预览: 1. 3d中的命中测试 我新建了一个空的窗口,用zam做了一个长方体,深度很小.然后导出xaml <Viewport3D x:Name="ZAM3DViewport3D& ...
- Remove WebCakeDesktop
WebCakeDesktop.Updater.exe 是广告程序,卸载步骤参考 http://malwaretips.com/blogs/webcake-desktop-updater-exe-rem ...
- asp.net web 后台判断提示框,点击'是'执行代码A(),点击'否'执行代码B()
html code <html xmlns="http://www.w3.org/1999/xhtml" > <head runat="server&q ...
- phpStorm无法使用svn1.8的解决办法
1.安装SVN的Command Lines Tools. 2.在phpStorm的SVN属性中,将Use Command Line Client填入:C:\Program Files\Tortoise ...
- Android开发(三十二)——延时
模拟延时 private class GetDataTask extends AsyncTask<Void, Void, String[]> { @Override protected S ...
- <《巴菲特之道 (第三版)》>读书笔记
以便宜的价格买入长期绩优的股票 他把对公司的投资看做是拥有公司的一部分股权,看重的是公司的长期经济价值 别人越是草率,我们越要加倍慎重 如果你发现自己已经在陷阱中,最重要的是想办法让自己不要再往下陷 ...
- 精通MVC网站、MVVM开发模式、Razor语法
http://www.cnblogs.com/powertoolsteam/p/MVC_one.html ASP.NET MVC (一)——深入理解ASP.NET MVC 以下是ASP.NET MVC ...
- vue开发资料
http://cn.vuejs.org/v2/guide/ (vue框架手册)https://router.vuejs.org/zh-cn/ (vue框架路由手册)https://github.com ...
- Ubuntu apt命令
http://www.tecmint.com/useful-basic-commands-of-apt-get-and-apt-cache-for-package-management/ apt-ca ...
- 如何将 Microsoft Bot Framework 链接至微信公共号
说到 Microsoft Bot Framework 其实微软发布了已经有一段时间了,有很多朋友可能还不太了解,微软Bot的功能今天我给大家简单的介绍一下,Bot Framework的开发基础以及如何 ...