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的更多相关文章

  1. CodeForces 558E(计数排序+线段树优化)

    题意:一个长度为n的字符串(只包含26个小字母)有q次操作 对于每次操作 给一个区间 和k k为1把该区间的字符不降序排序 k为0把该区间的字符不升序排序 求q次操作后所得字符串 思路: 该题数据规模 ...

  2. Codeforces 558E A Simple Task (计数排序&&线段树优化)

    题目链接:http://codeforces.com/contest/558/problem/E E. A Simple Task time limit per test5 seconds memor ...

  3. Codeforces 558E A Simple Task(计数排序+线段树优化)

    http://codeforces.com/problemset/problem/558/E Examples input 1 abacdabcda output 1 cbcaaaabdd input ...

  4. Nowcoder Hash Function ( 拓扑排序 && 线段树优化建图 )

    题目链接 题意 : 给出一个哈希表.其避免冲突的方法是线性探测再散列.现在问你给出的哈希表是否合法.如果合法则输出所有元素插入的顺序.如果有多解则输出字典序最小的那一个.如果不合法则输出 -1 分析 ...

  5. Codeforces 558E A Simple Task(权值线段树)

    题目链接  A Simple Task 题意  给出一个小写字母序列和若干操作.每个操作为对给定区间进行升序排序或降序排序. 考虑权值线段树. 建立26棵权值线段树.每次操作的时候先把26棵线段树上的 ...

  6. codeforces 558E A Simple Task 线段树

    题目链接 题意较为简单. 思路: 由于仅仅有26个字母,所以用26棵线段树维护就好了,比較easy. #include <iostream> #include <string> ...

  7. Codeforces 558E A Simple Task

    题意:给定一个字符串,以及m次操作,每次操作对字符串的一个子区间进行升序或降序排序,求m次操作后的串 考虑桶排,发现线段树可以模拟桶排的过程,所以对26个字母分别建立线段树即可 #include< ...

  8. Educational Codeforces Round 69 E - Culture Code (最短路计数+线段树优化建图)

    题意:有n个空心物品,每个物品有外部体积outi和内部体积ini,如果ini>outj,那么j就可以套在i里面.现在我们要选出n个物品的一个子集,这个子集内的k个物品全部套在一起,且剩下的物品都 ...

  9. [Codeforces 1197E]Culture Code(线段树优化建图+DAG上最短路)

    [Codeforces 1197E]Culture Code(线段树优化建图+DAG上最短路) 题面 有n个空心物品,每个物品有外部体积\(out_i\)和内部体积\(in_i\),如果\(in_i& ...

随机推荐

  1. SVO实时全局光照优化(里程碑MK2):Sparse Voxel Octree based Global Illumination (SVO GI)

    自主实现的实时渲染引擎,对标对象ue4/ce5,超越u3d/klayge.MK2版本侧重于质量与速度的均衡,以下上传示范均为实测截图,均为全分辨率(网页上显示缩小了)1080p/60fps.

  2. Putty & Ctrl+s 的魔咒

    Long long ago“ 某些旧的”哑终端“会在发送过来的数据太多,显示速度跟不上时发送一个Ctrl+s让对方等一下,然后再准备好继续显示时发送一个Ctrl+q.Putty“兼容”了这个特性.也有 ...

  3. DIV实现CSS 的placeholder效果

    placeholder是HTML5中input的属性,但该属性并不支持除input以外的元素   但我们可以使用Css before选择器来实现完全相同的效果 <!DOCTYPE html> ...

  4. <《基金经理投资笔记丛书4-1:投资是一种生活方式》>

    在中国股市每年能获得10%的收益已经是非常好了,但问题是大多数股民不认为这是一个很高的收益水平,尽管现实中大多数股民的收益状况比这要差很多. 投资中一个重要的心理陷阱是过度自信,过度自信的一个主要表现 ...

  5. 解决tkinter在windows上没有正确安装的问题

    问题 Can't find a usable tk.tcl in the following directories: 解决方法 加两个环境变量,在我的机器上是这样的 TCL_LIBRARY=D:\d ...

  6. 【jquery】基于 jquery 实现 ie 浏览器兼容 placeholder 效果

    placeholder 是 html5 新增加的属性,主要提供一种提示(hint),用于描述输入域所期待的值.该提示会在输入字段为空时显示,并会在字段获得焦点时消失.placeholder 属性适用于 ...

  7. Spring 注释 @Autowired 和@Resource 的区别

    Spring 注释 @Autowired 和@Resource 的区别 一. @Autowired和@Resource都可以用来装配bean,都可以写在字段上,或者方法上. 二. @Autowired ...

  8. SQL SERVER 2008 如何查询含有某关键词的表

    最新文章:Virson's Blog 文章来自:百度知道 /** 查询一个数据库中所有的数据中是否包含指定字符串 */ ) set @str='字符串' --要搜索的字符串 ) declare tb ...

  9. saiku 展示优化第二步(要诀和技巧)

    经历了上几篇博客的分享,可以无密码登录 : http://www.cnblogs.com/liqiu/p/5246015.html 随着使用的深入,公司需要将现有的报表平台与saiku整合,其中最便捷 ...

  10. Ubuntu 16.04 LTS更新

    Canonical今天正式发布了新版的Ubuntu系统,针对PC.笔记本.上网本.平板和智能手机各类设备.这次的Ubuntu 16.04代号为Xenial Xerus——这个代号是由Canonical ...