zoukankan      html  css  js  c++  java
  • 51nod1485 字母排序

    题目看这里

    也是非常简单的线段树合并模板题了,虽然实际上最好的做法因该是开数组合并(这样是均摊O(1)的)

    不过还算跑的快,第四

    #pragma GCC opitmize("O3")
    #pragma G++ opitmize("O3")
    #include<stdio.h>
    #include<string.h>
    #include<algorithm>
    #define mid (l+r>>1)
    #define N 100010
    using namespace std;
    struct tree{ int l,r,s; } s[1700010];
    int rt[N],n,m,cnt=0,rev[N]; char c[N];
    struct Set{
        int s[N<<2],M;
        void init(){
            for(M=1;M<=n;M<<=1); M--;
            for(int i=M+1;i<=n+M;++i) s[i]=1;
            for(int i=M;i;--i) s[i]=s[i<<1]+s[i<<1|1];
        }
        inline void remove(int x){ for(x+=M;x;x>>=1) --s[x]; }
        inline void insert(int x){ for(x+=M;x;x>>=1) ++s[x]; }
        inline int gPre(int x){
            if(s[x+M]) return x;
            for(x+=M;x;x>>=1)
                if((x&1)&&(s[x^1])){
                    for(--x;x<=M;x=(s[x<<1|1]?x<<1|1:x<<1));
                    return x-M;
                }
            return -1;
        }inline int gSuc(int x){
            if(s[x+M]) return x;
            for(x+=M;x;x>>=1)
                if((~x&1)&&(s[x^1])){
                    for(++x;x<=M;x=(s[x<<1]?x<<1:x<<1|1));
                    return x-M;
                }
            return n+1;
        }
    } T;
    inline void ps(int x){ s[x].s=s[s[x].l].s+s[s[x].r].s; }
    void insert(int l,int r,int& x,int k){
        x=++cnt; ++s[x].s;
        if(l==r) return;
        if(k<=mid) insert(l,mid,s[x].l,k);
            else insert(mid+1,r,s[x].r,k);
    }
    int merge(int l,int r,int r1,int r2){
        if(r1&&r2){
            if(l==r){ s[r1].s+=s[r2].s; return r1; }
            s[r1].l=merge(l,mid,s[r1].l,s[r2].l);
            s[r1].r=merge(mid+1,r,s[r1].r,s[r2].r);
            ps(r1);
            return r1;
        } else return r1+r2;
    }
    void split(int l,int r,int x,int k,int& r1,int& r2){
        if(s[x].s==k) { r1=x; r2=0; return; }
        if(l==r){
            r2=++cnt;
            s[r2].s=s[x].s-k;
            s[r1=x].s=k;
            return;
        }
        if(s[s[x].l].s>=k){
            int y,z;
            r2=++cnt;
            s[r2].r=s[x].r;
            s[r1=x].r=0;
            split(l,mid,s[x].l,k,y,z);
            s[r1].l=y; s[r2].l=z;
            ps(r1); ps(r2);
        } else {
            int y,z;
            r2=++cnt; r1=x;
            split(mid+1,r,s[x].r,k-s[s[x].l].s,y,z);
            s[r1].r=y; s[r2].r=z;
            ps(r1); ps(r2);
        }
    }
    void join(int l,int r,int o){
        int r1=T.gSuc(l+1);
        for(;r1<=r;r1=T.gSuc(r1)){
            merge(0,25,rt[l],rt[r1]);
            T.remove(r1);
        }
        rev[l]=o;
    }
    void cut(int p){
        if(p>n) return;
        int r1=T.gPre(p),r2;
        if(r1==p) return ;
        rev[p]=rev[r1]; r2=T.gSuc(p);
        if(!rev[p]) split(0,25,rt[r1],p-r1,rt[r1],rt[p]);
        else split(0,25,rt[r1],r2-p,rt[r1],rt[p]),swap(rt[r1],rt[p]);
        T.insert(p);
    }
    void print(int l,int r,int x,int o){
        if(!x) return;
        if(l==r){ for(int t=s[x].s;t--;) putchar(l+'a'); return; }
        if(o){ print(mid+1,r,s[x].r,o); print(l,mid,s[x].l,o); }
        else { print(l,mid,s[x].l,o); print(mid+1,r,s[x].r,o); }
    }
    int main(){
        scanf("%d%d%s",&n,&m,c+1); T.init();
        for(int i=1;i<=n;++i) insert(0,25,rt[i],c[i]-'a');
        for(int l,r,o;m--;){
            scanf("%d%d%d",&l,&r,&o);
            cut(l); 
            cut(r+1); 
            join(l,r,!o);
        }
        for(int x=1;x<=n;x=T.gSuc(x+1))
            print(0,25,rt[x],rev[x]);
    }

  • 相关阅读:
    面向对象的程序设计---组合练习
    一个简单的爬网页内容程序
    5.关于类和对象
    sql 查询至少连续n天下单的用户
    SQL 行转列 (统计每天,每个用户的消费金额)及sql 查询连续天数示例
    SQL 分组后进行相关统计
    SQL 分组内取前几名的问题
    JAVA-给定一组非负整数,重新排列它们的顺序使之组成一个最大的整数。
    SQL 刷题(CREATE FUNCTION,rank)
    机考刷题(SearchChar)
  • 原文地址:https://www.cnblogs.com/Extended-Ash/p/9477132.html
Copyright © 2011-2022 走看看