~~~题面~~~

题解:

  观察到字母只有26个,因此考虑对这26个字母分别维护,每个线段树维护一个字母,如果一个线段树的某个叶节点有值,表示当前叶节点所在位置的字母是现在这个线段树代表的字母。

  那么对于每一个操作,我们已经知道最后排好序之后肯定是按aaaabbbbccccddd……这样的序列排下去的(有些字母可能没有),每个字母都集中在自己的区间内。

  那么我们只需要知道每个字母之前的字母有多少个,就可以知道这个字母所在区间,因此按顺序修改。

  (以下操作均视为在每个字母对应的线段树上操作)先查询a的个数,并把当前修改的区间内赋0,然后把前1~tot_a全都赋1,表示这段区间是属于a的(全都放上1)。

  记在统计当前字母之前找到的字母个数之和为tot,则每次都是把当前线段树管理的字母全都移动到tot + 1~tot + 字母个数,相当于跟修改a类似的区间操作。只不过属于这个字母的区间的开始端点是tot + 1(其实a的情况也可以视作是tot + 1,因为这个时候tot = 0)

 #include<bits/stdc++.h>
using namespace std;
#define R register int
#define LL long long
#define AC 101000
#define ac 401000 int n, m, id, tot, add, t;
int l[ac], r[ac];
char s[AC], ans[AC]; int read()
{
int x = ;char c = getchar();
while(c > '' || c < '') c = getchar();
while(c >= '' && c <= '') x = x * + c -'', c = getchar();
return x;
} inline void upmin(int &a, int b)
{
if(b < a) a = b;
} inline void upmax(int &a, int b)
{
if(b > a) a = b;
} struct segament_tree{
int tree[ac], lazy[ac], id; inline void init()
{
memset(lazy, -, sizeof(lazy));
} inline void update(int x)
{
tree[x] = tree[x * ] + tree[x * + ];
} inline void pushdown(int x)
{
if(lazy[x] != -)
{
int ll = x * , rr = ll + ;
lazy[ll] = lazy[rr] = lazy[x];
if(!lazy[x]) tree[ll] = tree[rr] = ;
else
{
int mid = (l[x] + r[x]) >> ;
tree[ll] = mid - l[ll] + ;
tree[rr] = r[rr] - mid;
}
lazy[x] = -;
}
} void build(int x, int ll, int rr)
{
if(!id) l[x] = ll, r[x] = rr;
if(ll == rr)
{
if(s[ll] == id + 'a') tree[x] = ;
return ;
}
int mid = (ll + rr) >> ;
build(x * , ll, mid);
build(x * + , mid + , rr);
update(x);
} void find(int x, int ll, int rr)
{
if(!tree[x]) return ;
if(l[x] == ll && r[x] == rr){add += tree[x]; return ;}
pushdown(x);
int mid = (l[x] + r[x]) >> ;
if(rr <= mid) find(x * , ll, rr);
else if(ll > mid) find(x * + , ll, rr);
else
{
find(x * , ll, mid);
find(x * + , mid + , rr);
}
update(x);
} void change(int x, int ll, int rr)
{
if(l[x] == ll && r[x] == rr)
{
lazy[x] = t;
if(t) tree[x] = rr - ll + ;
else tree[x] = ;
return ;
}
pushdown(x);
int mid = (l[x] + r[x]) >> ;
if(rr <= mid) change(x * , ll, rr);
else if(ll > mid) change(x * + , ll, rr);
else
{
change(x * , ll, mid);
change(x * + , mid + , rr);
}
update(x);
} void get(int x)
{
if(!tree[x]) return ;
if(tree[x] == r[x] - l[x] + )
{
for(R i = l[x]; i <= r[x]; i ++) ans[i] = id + 'a';
return ;
}
pushdown(x);
if(tree[x * ]) get(x * );
if(tree[x * + ]) get(x * + );
} }T[]; void pre()
{
n = read(), m = read();
scanf("%s", s + );
for(R i = ; i < ; i ++)
T[i].id = i, T[i].init(), T[i].build(, , n);
} void check()
{
for(R i = ; i < ; i ++) T[i].get();
for(R i = ; i <= n; i ++) printf("%c", ans[i]);
printf("\n");
} void work()
{
int ll, rr, opt;
for(R i = ; i <= m; i ++)
{
// printf("%d\n", i);
ll = read(), rr = read(), opt = read(), tot = ll - ;
if(opt)
{
for(R j = ; j < ; j ++)
{
add = t = ;
T[j].find(, ll, rr);
if(!add) continue;
T[j].change(, ll, rr);
t = ;
T[j].change(, tot + , tot + add);
tot += add;
}
//check();
}
else
{
for(R j = ; j >= ; j --)
{
add = t = ;
T[j].find(, ll, rr);
if(!add) continue;
T[j].change(, ll, rr);
t = ;
T[j].change(, tot + , tot + add);
tot += add;
}
// check();
}
}
for(R i = ; i < ; i ++) T[i].get();
for(R i = ; i <= n; i ++) printf("%c", ans[i]);
printf("\n");
} int main()
{
//freopen("string6.in", "r", stdin);
pre();
work();
//fclose(stdin);
return ;
}

CF#312 558e A Simple Task的更多相关文章

  1. CF #312 E. A Simple Task 线段树

    题目链接:http://codeforces.com/problemset/problem/558/E 给一个字符串,每次对一个区间内的子串进行升序或者降序的排列,问最后字符串什么样子. 对于字符串排 ...

  2. 计数排序 + 线段树优化 --- Codeforces 558E : A Simple Task

    E. A Simple Task Problem's Link: http://codeforces.com/problemset/problem/558/E Mean: 给定一个字符串,有q次操作, ...

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

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

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

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

  5. Codeforces 558E A Simple Task

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

  6. codeforces 558E A Simple Task 线段树

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

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

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

  8. Codeforces Round #312 (Div. 2) E. A Simple Task 线段树

    E. A Simple Task 题目连接: http://www.codeforces.com/contest/558/problem/E Description This task is very ...

  9. Codeforces Round #312 (Div. 2) E. A Simple Task 线段树+计数排序

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

随机推荐

  1. java操作HDFS

    package com.lei.hadoop; import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.fs.Fil ...

  2. Docker - vim安装

    在使用docker容器时,有时候里边没有安装vim,敲vim命令时提示说:vim: command not found,这个时候就需要安装vim. apt-get install vim 若提示: R ...

  3. E2E test protractor selenium

    E2E Test和传统的Unit Test不同的是:(1)不涉及代码层面,不会去测试某段代码是否正确或者某行代码是否被覆盖(2)它是从用户的角度出发,用来测试一个应用的流程是否符合预期. 一 Sele ...

  4. SSM-最新pom.xml

    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/20 ...

  5. Linux命令应用大词典-第14章 显示登录用户

    14.1 w:详细查询已登录当前计算机的用户 14.2 who:显示已登录当前计算机用户的简单信息 14.3 whoami:显示与当前的有效ID相关联的用户名 14.4 logname:显示当前用户的 ...

  6. Linux命令应用大词典-第2章 获取帮助

    2.1 help:查看内部Shell命令帮助信息 2.2 man:显示在线手册页 2.3 manpath:查看和设置man手册页的查询路径 2.4 info:阅读info格式的文件 2.5 pinfo ...

  7. 【cover-view、cover-image】 覆盖组件说明

    cover-view.cover-image 这两类覆盖组件用于显示在一些特殊组件上方(map.video.canvas.camera.live-player.live-pusher). 这类组件一般 ...

  8. ObjectMapper的使用

    Jackson ObjectMapper类 ObjectMapper类是Jackson库的主要类它提供一些功能将Java对象转换成JSON结构,反之亦然它使用JsonParser和JsonGenera ...

  9. 【转】unity 热更新思路和实现

    声明:本文介绍的热更新方案是我在网上搜索到的,然后自己修改了一下,相当于是借鉴了别人的思路,加工成了自己的,在此感谢无私分享经验的朋友们. 想要使用热更新技术,需要规划设计好资源比较策略,资源版本,确 ...

  10. django 连接mysql报错

    原因: 问题1. 即从mysql5.7版本之后,默认采用了caching_sha2_password验证方式. 问题2.  然后在执行 python manage.py makemigrations依 ...