CSUOJ 1942 Sort String 线段树 操作变换
2017-06-06 21:14
239 查看
Description
Given a string S ,the length is n ,and It contains only lowercase English letters.Also given q queries each query is on the format i j k ,that means sort the substring consisting of the characters from i to j ,do it if k=1 non-decreasing order and if k=0 in non-increasing order.
Output the final string after all queries.
Input
First line contain two integers n, q (1 ≤ n ≤ 105105,0 ≤ q ≤ 50 000), for the string’s length and the number of queries.
Second line contains a string S.
Next q lines will contain three integers each i, j, k (1 ≤ i ≤ j ≤ n, k=1 or k=0 ).
Output
Output one line, the string S after all queries.
Sample Input
10 5 abacdabcda 7 10 0 5 8 1 1 4 0 3 6 0 7 10 1
Sample Output
cbcaaaabdd
题意是每一次可以对区间[L,R]里的数进行排序,在所有的操作做完之后输出最终的序列
第一想法肯定是线段树嘛,然后我想的是给区间打上这一段是升序还是逆序的lazy标记,最后输出答案
这个想法看上去很好,但是实际上是不行的,因为区间排序这个操作并不能很好的维护我们需要的值。
意思就是普通的区间加,和区间赋值,在实际储存的时候可能是分成若干段区间,在每个区间上都有一个lazy标记,但是排序分成若干段之后,没办法保证和在整个区间上排序是等价的,因此我就不会做了。。。。。。
正解是排序这一个操作可以转化为先查询后赋值,也就说先查询区间[L,R]上的每个字母出现的个数,然后按照相应的顺序给一段一段地给区间赋值相应的字母,这就要求我们的线段树维护26个值,代表26个字母的出现次数。只要这一点想到了,那基本上和普通的区间赋值,区间查询就没有什么很大的区别了。
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #define mid ((le+ri)>>1) #define lson (node<<1) #define rson (node<<1|1) #define lc lson,le,mid #define rc rson,mid+1,ri #define sc node,le,ri using namespace std; const int maxm=1E5+10; int n,q,ord,st[maxm*5][26],lazy[maxm*5],x,y,val,res[26]; void init(int node=1,int le=1,int ri=n),query(int node=1,int le=1,int ri=n), update(int node=1,int le=1,int ri=n),pushdown(int node,int le,int ri), pushup(int node),getans(int node=1,int le=1,int ri=n); char str[maxm]; int main(){ while(scanf("%d%d",&n,&q)!=EOF){ scanf("%s",str); init(); while(q--){ scanf("%d%d%d",&x,&y,&ord); memset(res,0,sizeof res); query(); if(ord!=1){ for(int i=25;i>=0;--i) if(res[i]){ y=x+res[i]-1,val=i; update(); x+=res[i]; } }else{ for(int i=0;i<26;++i) if(res[i]){ y=x+res[i]-1,val=i; update(); x+=res[i]; } } } getans(); printf("\n"); } return 0; } void pushdown(int node, int le, int ri){ if(lazy[node]!=-1){ lazy[lson]=lazy[rson]=lazy[node]; memset(st[lson],0,sizeof st[lson]); memset(st[rson],0,sizeof st[rson]); st[lson][lazy[node]]=mid-le+1; st[rson][lazy[node]]=ri-mid; lazy[node]=-1; } } void pushup(int node){ for(int i=0;i<26;++i) st[node][i]=st[lson][i]+st[rson][i]; } void init(int node, int le, int ri){ lazy[node]=-1; if(le==ri){ memset(st[node],0,sizeof st[node]); st[node][str[le-1]-'a']=1; }else{ init(lc); init(rc); pushup(node); } } void update(int node,int le,int ri){ if(ri<x||le>y)return; if(x<=le&&ri<=y){ lazy[node]=val; memset(st[node],0,sizeof st[node]); st[node][val]=ri-le+1; }else{ pushdown(sc); update(lc); update(rc); pushup(node); } } void getans(int node, int le, int ri){ if(le==ri){ for(int i=0;i<26;++i) if(st[node][i]){ printf("%c",i+'a'); return; } }else{ pushdown(sc); getans(lc); getans(rc); } } void query(int node,int le,int ri){ if(ri<x||le>y)return; if(x<=le&&ri<=y){ for(int i=0;i<26;++i) res[i]+=st[node][i]; }else{ pushdown(sc); query(lc); query(rc); } }
相关文章推荐
- 【J2me3D系列学习文章之三】(立即模式)对立方体进行变换操作-旋转、缩放、平移
- 线段树--数列操作
- 链接的最基本操作---链接颜色的变换
- hdu Just a Hook 线段树——成段操作 区域覆盖
- POJ 3225 Help with Intervals 线段树区间操作
- hdu 1698 Just a Hook (线段树区间操作,)
- 链接的最基本操作---链接颜色的变换
- hdu 2871 Memory Control(线段树的各种操作&Splay解法)
- 线段树 区域覆盖模版题 pku 3468 A Simple Problem with Integers 线段树——成段操作
- poj 3667 恶心到线段树,这是我到现在为止写过到最烦到线段树。 主要有 中间线段到操作
- 一些常见的二进制位的变换操作
- hdu3911线段树区间合并操作
- ImageMagick 图像风格变换 操作
- coj 1123 带区间操作的线段树(lazy)
- poj 1177 又是一道十分恶心到线段树。 主要是用线段树到区间操作。可以用来节省线性查找的时间。 离散化也十分好的一道题。
- [PKU 2777] 线段树(一) {概述 基本操作}
- 【J2me3D系列学习文章之三】(立即模式)对立方体进行变换操作-旋转、缩放、平移
- 链接的最基本操作---链接颜色的变换
- hdu 1166 敌兵布阵(线段树基本操作)
- poj 3468 很水的线段树lazy操作,为了理解hdu 3954 的 lazy做的。