zoukankan      html  css  js  c++  java
  • 校赛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;
    }
    
  • 相关阅读:
    Constants and Variables
    随想
    C#基础篇之语言和框架介绍
    Python基础19 实例方法 类方法 静态方法 私有变量 私有方法 属性
    Python基础18 实例变量 类变量 构造方法
    Python基础17 嵌套函数 函数类型和Lambda表达式 三大基础函数 filter() map() reduce()
    Python基础16 函数返回值 作用区域 生成器
    Python基础11 List插入,删除,替换和其他常用方法 insert() remove() pop() reverse() copy() clear() index() count()
    Python基础15 函数的定义 使用关键字参数调用 参数默认值 可变参数
    Python基础14 字典的创建修改访问和遍历 popitem() keys() values() items()
  • 原文地址:https://www.cnblogs.com/bryce1010/p/9386905.html
Copyright © 2011-2022 走看看