• 校赛F 比比谁更快(线段树)


    http://acm.cug.edu.cn/JudgeOnline/problem.php?cid=1153&pid=5
    这里写图片描述

    题意:给你一个字符串,各两个操作:
    ch=0,[l,r]降序
    ch=1,[l,r]升序

    如果是newer的话,应该会想用暴力,直接对区间sort,但是很明显是超时的(校赛怎么会这么简单呢!)
    很容易想到线段数,对于线段数,我们可以先理清一下知识点,线段树大概有三种操作:
    - 单点更新
    - 区间更新
    - RMQ

    显然这里要用区间更新的操作。
    区间更新有三大操作:

    build()建树
    update()更新
    query()求和
    sum[4*N]存储线段数节点

    但是一般的区间更新的线段数是区间加或者区间减等统一的操作,所以对于区间排序需要对区间查询模板更改一下。

    sum[4*N][26]来存储线段数节点
    setv[4*N]来存储当前区间覆盖的字母
    cnt[26]表示每个字母在当前区间出现的次数

    下面以样例“abacdabcda”为例进行阐述:
    首先是建树过程:
    这一部分计算出sum[4N][26]和setv[4N]的值

    其次,对于每一个查询,“l,r,ch”
    都要用query(int rt,int L,int R,int l,int r,int i)计算[l,r]区间cnt[i]的值。

    最后一步,对于每一个查询”l,r,ch”
    根据ch的值:
    做update(int rt,int L,int R,int l,int r,int i)
    如果ch=0,对[l,r]降序
    做法是:对cnt[i]数组从25->0 遍历,若cnt[i]>0,表示这个字符存在,且个数为cnt[i]个
    所以要把[l,l+cnt[i]]个位置都要修改为cnt[i]对应的字母,并把l(当前位置后移cnt[i]位)

    如果ch=1,对[l,r]升序
    做法相同,只是从[0->25]遍历。

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <cstdlib>
    #define ls (o<<1)
    #define rs (o<<1|1)
    #define lson ls,L,M
    #define rson rs,M+1,R
    using namespace std;
    
    typedef long long ll;
    const int N = 100005;
    const int sigma = 26;
    
    int sumv[N<<2][sigma], setv[N<<2]; //setv表示当前区间被覆盖的字母
    int cnt[26]; //每个坐标在当前区间出现的次数
    char str[N];
    
    void pushUp(int o) {
        for(int i = 0; i < sigma; i++) {
            sumv[o][i] = sumv[ls][i] + sumv[rs][i];
        }
    }
    
    void initNode(int o) {
        memset(sumv[o], 0, sizeof(sumv[o]));
    }
    
    void pushDown(int o, int L, int R) {
        int M = (L+R)/2;
        if(setv[o] != -1) {
            setv[ls] = setv[rs] = setv[o];
            initNode(ls);
            sumv[ls][setv[o]] = (M-L+1);
            initNode(rs);
            sumv[rs][setv[o]] = (R-M);
            setv[o] = -1;
        }
    }
    void build(int o, int L, int R) {
        if(L == R) {
            initNode(o);
            sumv[o][str[L]-'a'] = 1;
            setv[o] = str[L]-'a';
            return ;
        }
        setv[o] = -1;
        int M = (L+R)/2;
        build(lson);
        build(rson);
        pushUp(o);
    }
    
    int query(int o, int L, int R, int ql, int qr, int val) {
        if(ql <= L && R <= qr)
            return sumv[o][val];
        pushDown(o, L, R);
        int M = (L+R)/2, ret = 0;
        if(ql <= M) ret += query(lson, ql, qr, val);
        if(qr > M) ret += query(rson, ql, qr, val);
        return ret;
    }
    
    void modify(int o, int L, int R, int ql, int qr, int val) {
        if(ql <= L && R <= qr) {
            for(int i = 0; i < sigma; i++)
                sumv[o][i] = 0;
            setv[o] = val;
            sumv[o][setv[o]] = (R-L+1);
            return ;
        }
        pushDown(o, L, R);
        int M = (L+R)/2;
        if(ql <= M) modify(lson, ql, qr, val);
        if(qr > M) modify(rson, ql, qr, val);
        pushUp(o);
    }
    
    void getStr(int o, int L, int R) {
        if(L == R) {
            printf("%c", (char)('a'+setv[o]));
            return ;
        }
        pushDown(o, L, R);
        int M = (L+R)/2;
        getStr(lson);
        getStr(rson);
    }
    
    int n, q;
    int main() {
        while(scanf("%d%d", &n, &q) != EOF) {
            scanf("%s", str+1);
            build(1, 1, n);
    
            int ql, qr, ch;
            while(q--) {
                scanf("%d%d%d", &ql, &qr, &ch);
                for(int i = 0; i < sigma; i++)
                    cnt[i] = query(1, 1, n, ql, qr, i);
    
                int pos = ql;
                if(ch == 1) {
                    for(int i = 0; i < sigma; i++) {
                        if(cnt[i] > 0)
                            modify(1, 1, n, pos, pos+cnt[i]-1, i);
                        pos += cnt[i];
                    }
                }else {
                    for(int i = sigma-1; i >= 0; i--) {
                        if(cnt[i] > 0)
                            modify(1, 1, n, pos, pos+cnt[i]-1, i);
                        pos += cnt[i];
                    }
                }
            }
            getStr(1, 1, n); puts("");
        }
        return 0;
    }
    
  • 相关阅读:
    Java泛型学习笔记
    Java泛型学习笔记
    Java泛型学习笔记
    Java泛型学习笔记
    Java泛型学习笔记
    Java泛型学习笔记
    Java泛型学习笔记
    有1到100共100个数, 从1开始, 每隔1, 2, 3... 个数拿走一个数, 最后剩下几?(约瑟夫环)
    推荐一个自动抽取pdf高亮笔记的web应用
    协程
  • 原文地址:https://www.cnblogs.com/bryce1010/p/9386905.html
Copyright © 2020-2023  润新知