zoukankan      html  css  js  c++  java
  • string

    string( (starstar ))

    • 时限:(1s) 内存:(256M)

    Descrption

    • 给定一个由小写字母组成的字符串 (s)。有 (m) 次操作,每次操作给定 (3) 个参数 (l,r,x)。如果 (x=1),将 (s[l]sim s[r]) 升序排序;如果 (x=0),将 (s[l]~s[r]) 降序排序。你需要求出最终序列。

    Input

    • 第一行两个整数 (n,m),表示字符串长度为 (n),有 (m) 次操作。
    • 第二行一个字符串 (s)
    • 接下来 (m) 行每行三个整数 (l,r,x)

    Output

    • 一行一个字符串表示答案。

    Sample Input

    5 2
    cabcd
    1 3 1
    3 5 0
    

    Sample Output

    abdcc
    

    Hint

    • 对于 (40\%) 的数据,(n,m<=1000)
    • 对于 (100\%) 的数据,(n,m<=100000)
    • 来源:

    分析

    • 因为字符串全是小写字母,所以不同的字符最多只有 (26) 个,我们可以用 (1sim 26) 代替。可以建一棵线段树,把各个叶子节点就是对应字母的值。
    • 对于区间排序,实际上我们不需要真的排序,只要知道区间内有多少个字符,每个字符有多少,再逐一赋值即可。对于一个节点,如果其两个子节点的数值相同,那么它自己也附上相同的值。
    • 修改时,如果一个区间均是同一个值,不需要递归到叶子,可以向类似的 (lazy) 标记一样进行处理,如果区间不完全重合,那么就要类似 (lazy) 标记一样,先 (pushdown)
    • 对于每一次操作,求其区间内各个字母的次数,如果升序就从 (asim z) ,降序就从 (zsim a) 循环,依次替换线段树中的位置。

    Code

    #include <bits/stdc++.h>
    const int maxn=1e5+7;
    struct tree{
        int l,r,v;
    }a[maxn<<2];
    char st[maxn];
    int n,m,f[29];
    void Build(int l,int r,int rt){
        a[rt].l=l; a[rt].r=r;
        if(l==r){
            a[rt].v=st[l]-'a'+1; return;
        }
        int mid=(l+r)>>1;
        Build(l,mid,rt<<1); Build(mid+1,r,rt<<1|1);
        if(a[rt<<1].v==a[rt<<1|1].v)//如果左右子树字母相同则更新父区间
            a[rt].v=a[rt<<1].v;
    }
    void get_f(int l,int r,int rt){//查找区间l~r 出现的字母即其个数
        if(a[rt].l>=l && a[rt].r<=r && a[rt].v){//a[rt].v!=0才表示区间内字符一样
            f[a[rt].v]+=a[rt].r-a[rt].l+1; return;//f[i]:表示字母i的个数
        }
        if(a[rt].v)//类似的pushdown操作
            a[rt<<1].v=a[rt<<1|1].v=a[rt].v;
        int mid=(a[rt].l+a[rt].r)>>1;
        if(mid>=l) get_f(l,r,rt<<1);
        if(mid<r) get_f(l,r,rt<<1|1);
    }
    void Work(int l,int r,int rt,int x){//把区间[l,r]全部赋值为x
        if(a[rt].l>=l&&a[rt].r<=r||a[rt].v==x){
            a[rt].v=x; return;
        }
        if(a[rt].v){//类似pushdown
            a[rt<<1].v=a[rt<<1|1].v=a[rt].v;
            a[rt].v=0;//rt未包含在内说明会有部分不同
        }
        int mid=(a[rt].l+a[rt].r)/2;
        if(l<=mid) Work(l,r,rt<<1,x);
        if(mid<r) Work(l,r,rt<<1|1,x);
        if(a[rt<<1].v==a[rt<<1|1].v)//左右子区间元素相同,rt区间也是同一个字母
            a[rt].v=a[rt<<1].v;
    }
    void Print(int x){
        if(a[x].v){
            for(int i=a[x].l; i<=a[x].r; i++)
                printf("%c",a[x].v+'a'-1); return;
        }
        Print(x<<1),Print(x<<1|1);
    }
    void Solve(){
        scanf("%d%d",&n,&m);
        scanf("%s",st+1);
        Build(1,n,1);
        for(int i=1; i<=m; i++){
            int l,r,x;
            scanf("%d%d%d",&l,&r,&x);
            memset(f,0,sizeof(f));
            get_f(l,r,1);
            if(x){
                for(int j=1; j<=26; j++)
                    if(f[j])
                        Work(l,l+f[j]-1,1,j),l+=f[j];
            }
            else{
                for(int j=26; j>=1; j--)
                    if(f[j])
                        Work(l,l+f[j]-1,1,j),l+=f[j];
            }
        }
        Print(1);
    }
    int main(){
        Solve();
        return 0;
    }
    
  • 相关阅读:
    戴德金分割第6页
    自己总结的学习方法
    自己总结的选股方法和建仓方法
    自编通达信公式集合
    电脑目录设置
    1·0天内跳空缺口的公式
    springsecurity
    java开发 日志框架选择
    javaFramwork title
    idea git忽略文件
  • 原文地址:https://www.cnblogs.com/hbhszxyb/p/13414098.html
Copyright © 2011-2022 走看看