[Codeforces Round#312 Div.2] A Simple Task 【线段树+lazy_tag】

[Codeforces Round#312 Div.2] A Simple Task

题目描述
给出一个长度为n的字符串,给出q个区间,要求依次将区间内的字符按非升/非降进行排序,输出最后的字符串。
数据范围

1n105,0q50000

样例输入
10 5
abacdabcda
7 10 0
5 8 1
1 4 0
3 6 0
7 10 1
样例输出
cbcaaaabdd

其实一开始我是不愿意写26个线段树的。。。
我固执地使用自己的单个线段树版,每次区间都需要从 1 循环到26当前区间的 cnt[i] 这个直接导致了我做此题用了半天!!8个小时!!从test9 TLE 升级到test22 TLE 最后升级到test53 TLE再也切不动了。。。

正题:

用26个线段树维护每个区间该字符的个数,(从小到大/从大到小)更替这个区间的字符串,所以就不用sort排序了,需要用lazy懒标记,2000+ms过。【该用空间的地方就用0 0】
对了,还有一个不起眼的小优化,也不知道它为我最后的AC贡献了多少时间。。。就是如果操作中出现两个区间前者被后者框在了里面,就可以删去前者,我用了手写栈。。。

码:

#include<iostream>
#include<cstring>
#include<cstdio>
#include<string>
#define LCH(i) (2 * i)
#define RCH(i) (2 * i + 1)
const int maxn = 1e5;
const int maxl = 26;
const int maxo = 50000;
using namespace std;

struct OP
{
    int l, r, ope;
}op[maxo + 5], sta[maxo + 5];

struct T
{
    int lc, rc, cnt;
    int size(){
        if(lazy == 1)return rc - lc + 1;
        else return 0;
    }
    int lazy;
}tree[maxl + 5][maxn * 4];

int n, q, top, tmp[maxl + 5];
char str[maxn + 5];

void del()
{
    for(int i = 1; i <= q; i ++){
        while(top > 0 && sta[top].l >= op[i].l && sta[top].r <= op[i].r) -- top;
        sta[++ top] = op[i];
    }
    for(int i = 1; i <= top; i ++)
        op[i] = sta[i];
    q = top;
}

void built(int i, int l, int r, int alpha)
{
    tree[alpha][i].lc = l, tree[alpha][i].rc = r;
    if(l == r){
        if(str[l] - 'a' == alpha)tree[alpha][i].cnt ++;
        return ;
    }
    int mid = (l + r) / 2;
    built(LCH(i), l, mid, alpha);
    built(RCH(i), mid + 1, r, alpha);
    tree[alpha][i].cnt = tree[alpha][LCH(i)].cnt + tree[alpha][RCH(i)].cnt;
    return;
}

void query(int i, int l, int r, int alpha){
    if(tree[alpha][i].rc < l || tree[alpha][i].lc > r)return ;
    if(tree[alpha][i].lc >= l && tree[alpha][i].rc <= r){
        tmp[alpha] += tree[alpha][i].cnt;
        tree[alpha][i].lazy = 1;
        return;
    }
    else {
        if(tree[alpha][i].lazy){
            tree[alpha][LCH(i)].lazy = tree[alpha][i].lazy;
            tree[alpha][RCH(i)].lazy = tree[alpha][i].lazy;
            tree[alpha][LCH(i)].cnt = tree[alpha][LCH(i)].size();
            tree[alpha][RCH(i)].cnt = tree[alpha][RCH(i)].size();
            tree[alpha][i].lazy = 0;
        }
        query(LCH(i), l, r, alpha);
        query(RCH(i), l, r, alpha);
    }
}

void update(int i, int l, int r, int alpha, int val)
{
    if(tree[alpha][i].lc > r || tree[alpha][i].rc < l)return;
    if(tree[alpha][i].lc >= l && tree[alpha][i].rc <= r){
        tree[alpha][i].lazy = val;
        tree[alpha][i].cnt = tree[alpha][i].size();
        return;
    }
    else {
        if(tree[alpha][i].lazy){
            tree[alpha][LCH(i)].lazy = tree[alpha][i].lazy;
            tree[alpha][RCH(i)].lazy = tree[alpha][i].lazy;
            tree[alpha][LCH(i)].cnt = tree[alpha][LCH(i)].size();
            tree[alpha][RCH(i)].cnt = tree[alpha][RCH(i)].size();
            tree[alpha][i].lazy = 0;
        }
        update(LCH(i), l, r, alpha, val);
        update(RCH(i), l, r, alpha, val);
        tree[alpha][i].cnt = tree[alpha][LCH(i)].cnt + tree[alpha][RCH(i)].cnt;
        return;
    }
}

int main()
{
    scanf("%d %d\n", &n, &q);
    gets(str + 1);
    for(int i = 1; i <= q; i ++)
        scanf("%d%d%d", &op[i].l, &op[i].r, &op[i].ope);
    del();//小优化
    for(int i = 0; i < maxl; i ++)
        built(1, 1, n, i);

    int xlen;
    for(int i = 1; i <= q; i ++){
        for(int j = 0; j < maxl; j ++){
            query(1, op[i].l, op[i].r, j);
            update(1, op[i].l, op[i].r, j, 2);
        }
        xlen = op[i].l;
        if(op[i].ope){
            for(int j = 0; j < maxl; j ++){
                if(!tmp[j])continue;
                update(1, xlen, xlen + tmp[j] - 1, j, 1);
                while(tmp[j]){//更新当前字符串
                    str[xlen ++] = j + 'a';
                    tmp[j] --;
                }
            }
        }
        else{
            for(int j = maxl - 1; j >= 0; j --){
                if(!tmp[j])continue;
                update(1, xlen, xlen + tmp[j] - 1, j, 1);
                while(tmp[j]){//更新当前字符串
                    str[xlen ++] = j + 'a';
                    tmp[j] --;
                }
            }
        }
        //printf("%s", str + 1);
        //puts("");
    }
    printf("%s", str + 1);
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值