题目链接:http://codeforces.com/contest/558/problem/E
E. A Simple Task
time limit per test
5 seconds
memory limit per test
512 megabytes
input
standard input
output
standard output
 
This task is very simple. Given a string S of length n and q queries
 each query is on the format i j k which
 means sort the substring consisting of the characters from i to j in
 non-decreasing order if k = 1 or in non-increasing order if k = 0.
Output the final string after applying the queries.
 
Input
The first line will contain two integers n, q (1 ≤ n ≤ 105, 0 ≤ q ≤ 50 000),
 the length of the string and the number of queries respectively.
Next line contains a string S itself. It contains only lowercase English letters.
Next q lines will contain three integers each i, j, k (1 ≤ i ≤ j ≤ n, ).
 
Output
Output one line, the string S after applying the queries.
 
Sample test(s)
 
input
10 5
abacdabcda
7 10 0
5 8 1
1 4 0
3 6 0
7 10 1
 
output
cbcaaaabdd
 
input
10 1
agjucbvdfk
1 10 1
 
output
abcdfgjkuv
 
 
Note
First sample test explanation:
题意:就是说给你一个n长度字符串,进行q次操作,k=1时要对着一个区间的字符进行
非递减排序,k=2时相反,最后输出操作后的字符串
思路:正常写法肯定超时,那就可肯定要优化,采取线段树优化查询和更改都是log2(n)
线短路算法:https://blog.csdn.net/zearot/article/details/48299459
代码有解析,我就不多说了!
上代码:
  1. #include<stdio.h>
  2. #include<iostream>
  3. #include<algorithm>
  4. #include<string.h>
  5. using namespace std;
  6. const int maxn=;
  7. #define lson(x) x<<1
  8. #define rson(x) x<<1|1
  9. #define L(x) tree[x].l;
  10. #define R(x) tree[x].r;
  11. #define Hav[x] tree[x].hav
  12. #define Lazy(x) tree[x].lazy
  13. char ans[maxn],str[maxn];
  14. int cnt[];
  15. struct Segtree //声明26棵树来存每个字母
  16. {
  17. int l,r,hav,m,lazy;
  18. }tree[][maxn<<];
  19. void pushup(int root,int id) //区间求和,因为一个父区间中某个字母的个数是所有子区间字母个数的和
  20. {
  21. tree[id][root].hav=tree[id][root<<].hav+tree[id][root<<|].hav;
  22. }
  23. void pushdown(int root,int id) //下推标记,在这过程中将所个区间全部填满,(为什么填满要看主函数)
  24. {
  25. if(tree[id][root].lazy<) return;
  26. tree[id][root<<].hav=(tree[id][root<<].r-tree[id][root<<].l)*tree[id][root].lazy;
  27. tree[id][root<<].lazy=tree[id][root].lazy;
  28. tree[id][root<<|].hav=(tree[id][root<<|].r-tree[id][root<<|].l)*tree[id][root].lazy;
  29. tree[id][root<<|].lazy=tree[id][root].lazy;
  30. tree[id][root].lazy=-; //父标记删除,子标记续上
  31. }
  32. //void build(int l,int r,int root,int id)
  33. //{ //建一颗总长度为r-l+1的树,其中第一个父节点区间长度最大,处于树的顶端,剩下的依次减少,且相互之间不能重复
  34. // int mid=(l+r)>>1;
  35. // tree[id][root].m=mid; //记录中间节点,中后可能会使用(我后面代码有的时候没有使用)
  36. // tree[id][root].l=l;
  37. // tree[id][root].r=r;
  38. // tree[id][root].lazy=-1; //标记复原位
  39. // if(r-l==1) //按模板来说应该是r==l时才进入,但是主函数中字符数组存值是从0--n-1,
  40. // { //但是我建图的时候用的是1--n+1,其实n+1并没有,所以就相当于这个时候已经到树的最底部了
  41. // //这一点多做一些题就会学到好些骚操作
  42. // tree[id][root].hav=(str[l-1]=='a'+id);
  43. // return;
  44. // }
  45. // build(l,mid,root<<1,id);
  46. // build(mid+1,r,root<<1|1,id);
  47. // pushup(root,id);
  48. //}
  49. void build(int l,int r,int n,int id)
  50.  
  51. {
  52.  
  53. int m=(l+r)>>;
  54.  
  55. tree[id][n].l=l;
  56.  
  57. tree[id][n].r=r;
  58.  
  59. tree[id][n].m=m;
  60.  
  61. tree[id][n].lazy=-;
  62. if(r-l==)
  63. {
  64. tree[id][n].hav=(str[l-]=='a'+id);
  65. return;
  66. }
  67.  
  68. if(r-l==)
  69.  
  70. {
  71.  
  72. tree[id][n].hav=(str[l-]=='a'+id);
  73.  
  74. return;
  75.  
  76. }
  77.  
  78. build(l,m,n<<,id);
  79. //因为当(n+n+1)>>1的值为n,一旦加一,那就超范围了
  80. //而且本题再给树底部赋值的时候是用str[l-1]来判断的,由此可见,Segtree结构体里面存的范围和实际操作相差一
  81. build(m,r,n<<|,id); //————————我的代码是这里错了,我写的是“m+1”——————————————
  82.  
  83. pushup(n,id);
  84.  
  85. }
  86. //void update(int l,int r,int root,int ops,int id)
  87. //{ //更新操作,把给出的这一部分区间全部填满(这里说的全部填满就是tree[id][root].hav=(tree[id][root].r-tree[id][root].l)*1(数字);)
  88. // if(tree[id][root].l==l && tree[id][root].r==r)
  89. // {
  90. // tree[id][root].hav=(tree[id][root].r-tree[id][root].l)*ops;
  91. // tree[id][root].lazy=ops;
  92. // return;
  93. // }
  94. // //先下推标记,要不然有的区间还没更新就去查找就会错
  95. // pushdown(root,id);
  96. // int mid=(tree[id][root].l+tree[id][root].r)>>1;
  97. // if(r<=mid) //满足这一个或下一个条件就说明所求区间就在此父节点的一个子区间内
  98. // {
  99. // update(l,r,root<<1,ops,id);
  100. // }
  101. // else if(l>=mid)
  102. // {
  103. // update(l,r,root<<1|1,ops,id);
  104. // }
  105. // else
  106. // {
  107. // update(l,mid,root<<1,ops,id);
  108. // update(mid,r,root<<1|1,ops,id);
  109. // }
  110. // pushup(root,id);
  111. //}
  112. void update(int l,int r,int n,int op,int id)
  113.  
  114. {
  115.  
  116. if(tree[id][n].l==l && tree[id][n].r==r)
  117.  
  118. {
  119.  
  120. tree[id][n].hav=(tree[id][n].r-tree[id][n].l)*op;
  121.  
  122. tree[id][n].lazy=op;
  123.  
  124. return;
  125.  
  126. }
  127.  
  128. pushdown(n,id);
  129.  
  130. if(r<=tree[id][n].m)update(l,r,n<<,op,id);
  131.  
  132. else if(l>=tree[id][n].m)update(l,r,n<<|,op,id);
  133.  
  134. else
  135.  
  136. {
  137.  
  138. update(l,tree[id][n].m,n<<,op,id);
  139.  
  140. update(tree[id][n].m,r,n<<|,op,id);
  141.  
  142. }
  143.  
  144. pushup(n,id);
  145.  
  146. }
  147. int query(int l,int r,int n,int id)
  148.  
  149. {
  150.  
  151. if(tree[id][n].l==l && tree[id][n].r==r)
  152.  
  153. return tree[id][n].hav;
  154.  
  155. pushdown(n,id);
  156.  
  157. if(r<=tree[id][n].m)
  158.  
  159. return query(l,r,n<<,id);
  160.  
  161. if(l>=tree[id][n].m)
  162.  
  163. return query(l,r,n<<|,id);
  164.  
  165. return query(l,tree[id][n].m,n<<,id)
  166.  
  167. +query(tree[id][n].m,r,n<<|,id); //————————这里的tree[id][n].m也不能多加一————————————————
  168.  
  169. }
  170. //int query(int l,int r,int root,int id)
  171. //{ //查找和更新大多都一样
  172. // if(tree[id][root].l==l && tree[id][root].r==r)
  173. // {
  174. // return tree[id][root].hav;
  175. // }
  176. // pushdown(root,id);
  177. // int mid=(tree[id][root].l+tree[id][root].r)>>1;
  178. // if(r<=mid) return query(l,r,root<<1,id);
  179. // else if(l>=mid) return query(l,r,root<<1|1,id);
  180. // return query(l,mid,root<<1,id)+query(mid+1,r,root<<1|1,id);
  181. //}
  182. //int main()
  183. //{
  184. // int n,q;
  185. // scanf("%d%d",&n,&q);
  186. // scanf("%s",str);
  187. // for(int i=0;i<26;++i) build(1,n+1,1,i);
  188. // int l,r,k;
  189. // while(q--)
  190. // {
  191. // scanf("%d%d%d",&l,&r,&k);
  192. // for(int i=0;i<26;++i)
  193. // {
  194. // cnt[i]=query(l,r+1,1,i);
  195. // update(l,r+1,1,0,i);
  196. // }
  197. // if(k==1)
  198. // {
  199. // int loc=l;
  200. // for(int i=0;i<26;++i)
  201. // {
  202. // if(cnt[i]) update(loc,loc+cnt[i],1,1,i);
  203. // loc+=cnt[i];
  204. // }
  205. // }
  206. // else
  207. // {
  208. // int loc=l;
  209. // for(int i=25;i>=0;--i)
  210. // {
  211. // if(cnt[i]) update(loc,loc+cnt[i],1,1,i);
  212. // loc+=cnt[i];
  213. // }
  214. // }
  215. // }
  216. // for(int i=1;i<=n;++i)
  217. // {
  218. // for(int j=0;j<26;++j)
  219. // {
  220. // if(query(i,i+1,1,j))
  221. // {
  222. // ans[i-1]='a'+j;
  223. // break;
  224. // }
  225. // }
  226. // }
  227. // printf("%s\n",ans);
  228. // return 0;
  229. //}
  230. int main()
  231.  
  232. {
  233.  
  234. int n,q;
  235.  
  236. scanf("%d%d",&n,&q);
  237.  
  238. scanf("%s",str);
  239.  
  240. for(int i=;i<;i++)build(,n+,,i);
  241. //先按照原来的字符在数组里面的顺序对线段树进行填充
  242. int l,r,k;
  243.  
  244. while(q--)
  245.  
  246. {
  247.  
  248. scanf("%d%d%d",&l,&r,&k);
  249.  
  250. for(int i=;i<;i++)
  251.  
  252. {
  253.  
  254. cnt[i]=query(l,r+,,i);
  255. //找出来这个被要求的区间内有多少这个字母
  256. update(l,r+,,,i);
  257. //再把这个区间全部初始化为0
  258. }
  259. //判断一下是让顺序还是逆序,如果是按顺序排,那就让填充的时候字母正着填充
  260. if(k==)
  261.  
  262. {
  263.  
  264. int loc=l;
  265.  
  266. for(int i=;i<;i++)
  267.  
  268. {
  269.  
  270. if(cnt[i]>)update(loc,loc+cnt[i],,,i);
  271.  
  272. loc+=cnt[i];
  273.  
  274. }
  275.  
  276. }
  277.  
  278. else
  279.  
  280. {
  281.  
  282. int loc=l;
  283.  
  284. for(int i=;i>=;i--)
  285.  
  286. {
  287.  
  288. if(cnt[i]>)update(loc,loc+cnt[i],,,i);
  289.  
  290. loc+=cnt[i];
  291.  
  292. }
  293.  
  294. }
  295.  
  296. }
  297. //这个就相当于一个位置一个位置的查询
  298. for(int i=;i<=n;i++)
  299.  
  300. for(int j=;j<;j++)
  301.  
  302. if(query(i,i+,,j))
  303.  
  304. {
  305.  
  306. ans[i-]='a'+j;
  307.  
  308. break;
  309.  
  310. }
  311.  
  312. printf("%s\n",ans);
  313.  
  314. return ;
  315.  
  316. }
 

Codeforces 558E A Simple Task (计数排序&&线段树优化)的更多相关文章

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

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

  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/problemset/problem/558/E Examples input 1 abacdabcda output 1 cbcaaaabdd input ...

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

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

  5. Codeforces 1603D - Artistic Partition(莫反+线段树优化 dp)

    Codeforces 题面传送门 & 洛谷题面传送门 学 whk 时比较无聊开了道题做做发现是道神题( 介绍一种不太一样的做法,不观察出决策单调性也可以做. 首先一个很 trivial 的 o ...

  6. Codeforces.1045A.Last chance(最大流ISAP 线段树优化建图)

    题目链接 \(Description\) 你需要用给定的\(n\)个武器摧毁\(m\)架飞船中的某一些.每架飞船需要被摧毁恰好一次. 武器共三种:1.可以在给定的集合中摧毁一架飞船:2.可以摧毁区间\ ...

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

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

  8. codeforces 558E A Simple Task 线段树

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

  9. Codeforces 558E A Simple Task

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

随机推荐

  1. kettle变量(var变量)

    设置变量/set varibale 1.定义变量(子转换): 原始数据 设置获取变量:点击获取字段,自动获取变量名称和字段名称 引用变量: 输出: kettle.properties 文件存储在.ke ...

  2. ArrayList如何扩容?

    1.调用ArrayList的参构造方法,此时集合内部是一个空数组 transient Object[] elementData; private static final Object[] DEFAU ...

  3. 测试体验Centrifugo

    今天尝试用 centrifugo 来做一个在聊天室,以前用workerman做过,相对来说 workerman的配置就显得复杂多了,需要自己搭建PHP环境, 而 centrifugo 就清爽多了,官网 ...

  4. iOS 使用百度的人脸识别登录验证,解决认证失败不跳转界面连续认证,认证相似度对比

    在使用百度人脸识别出现的问题:小米6调用摄像机是黑白的一个情况,iOS上会出现识别准确性上的问题(多次代开认证,会通过) 人脸识别(活体验证): 1.芝麻认证 : 0.4元/次,需要企业企业认证.不能 ...

  5. django xadmin(2) 在xadmin基础上完成自定义页面

    1.在xadmin.py,GlobalSettings中自定义菜单 2.自定义视图函数,并获取原来的菜单等一下信息(主要是为了用xadmin的模板),具体的自己看xadmin源码 3.在adminx. ...

  6. MySQL逻辑备份mysqldump

    MySQL 备份之 mysqldump mysqldump mysqldump工具备份: 本质:导出的是SQL语句文件 优点:不论是什么存储引擎,都可以用mysqldump备成SQL语句 缺点:速度较 ...

  7. windows下提权基础

    拿到webshell很多时候代表渗透的开始,下面带来windows提权基础 环境:虚拟机 win7系统 首先:查看权限whoami 我们知道windows的高权限应该是administrator和sy ...

  8. ubuntu下adb的使用以及开启黑域

    ubuntu使用adb开启黑域 刷了原生后经好友推荐, 黑域对于App的管控效果还是很不错的 adb的安装 此处顺带着就把fastboot也安装了 sudo apt update sudo apt i ...

  9. 树莓派wiringPi,BCM,BOARD编码对应管脚

    wiringPi,BCM,BOARD编码 由于上课需要, 嵌入式学习从树莓派开始 树莓派中执行: $> gpio readall 即可得到关于树莓派管脚的各种信息 上面的图可能不是特别清楚, 可 ...

  10. R语言入门(2)-数据对象

    数据对象 创建向量相关的方法 R语言的向量用法非常像python, 就比如这个seq(0,10,2), 从0到10, 步长为2, 涉及到的元素作为向量里的内容进行创建. 这里的用法非常像Matlab, ...