[线段树] codeforces 558E. A Simple Task

题意:

给一个长度n的字符串,q次操作,每次操作把[l,r]排序,k=0非递增,k=1非递减。

题解:

采用计数排序的复杂度是O(n?q),无法通过,但有所启示。

可以看出计数就是区间求和,排序就是区间更新,可以用线段树维护。

做法是建立26棵线段树,第i棵树维护第i个字母的位置信息。

计数时,在26棵线段树内分别做一次查询,排序时根据递增还是递减,把相应的区间赋值为相应的字母。

#include<bits/stdc++.h>
#define lson rt<<1,l,mid
#define rson rt<<1|1,mid+1,r
using namespace std;
const int N = 1e5+5;
char s[N];
struct SegTree{
    int tree[N<<2], lazy[N<<2];
    void push_up(int rt){ tree[rt] = tree[rt<<1] + tree[rt<<1|1]; }
    void push_down(int rt, int l, int r){
        if(lazy[rt] != -1){
            int mid = (l+r) >> 1;
            tree[rt<<1] = (mid-l+1)*lazy[rt];
            tree[rt<<1|1] = (r-mid)*lazy[rt];
            lazy[rt<<1] = lazy[rt<<1|1] = lazy[rt];
            lazy[rt] = -1;
        }
    }
    void build(int rt, int l, int r, char c){
        tree[rt] = 0, lazy[rt] = -1;
        if(l == r){
            tree[rt] = (s[l] == c);
            return;
        }
        int mid = (l+r) >> 1;
        build(lson, c);
        build(rson, c);
        push_up(rt);
    }
    void update(int rt, int l, int r, int ql, int qr, int v){
        if(ql <= l && qr >= r){
            tree[rt] = (r-l+1)*v;
            lazy[rt] = v;
            return;
        }
        push_down(rt, l, r);
        int mid = (l+r) >> 1;
        if(ql <= mid) update(lson, ql, qr, v);
        if(qr > mid) update(rson, ql, qr, v);
        push_up(rt);
    }
    int query(int rt, int l, int r, int ql, int qr){
        if(ql <= l && qr >= r) return tree[rt];
        push_down(rt, l, r);
        int res = 0, mid = (l+r) >> 1;
        if(ql <= mid) res += query(lson, ql, qr);
        if(qr > mid) res += query(rson, ql, qr);
        push_up(rt);
        return res;
    }
    void print(int rt, int l, int r, char c){
        if(l == r){
            if(tree[rt]) s[l] = c;
            return;
        }
        push_down(rt, l, r);
        int mid = (l+r) >> 1;
        if(tree[rt]) print(lson, c), print(rson,c);
        push_up(rt);
    }
}tr[30];
void print(int n){
    for(int i = 0; i < 26; ++i) tr[i].print(1, 1, n, i+‘a‘);
    s[n+1] = 0;
    puts(s+1);
}
int main(){
    int n, q;
    scanf("%d%d", &n, &q);
    scanf("%s", s+1);
    for(int i = 0; i < 26; ++i) tr[i].build(1, 1, n, ‘a‘+i);
    while(q--){
        int l, r, k;
        scanf("%d%d%d", &l, &r, &k);
        int cot[30] = {0};
        for(int i = 0; i < 26; ++i) cot[i] = tr[i].query(1, 1, n, l, r);
        for(int i = 0; i < 26; ++i) tr[i].update(1, 1, n, l, r, 0);
        if(k == 0){
            for(int i = 25; i >= 0; --i){
                if(!cot[i]) continue;
                tr[i].update(1, 1, n, l, l+cot[i]-1, 1);
                l += cot[i];
            }
        }
        else{
            for(int i = 0; i <= 25; ++i){
                if(!cot[i]) continue;
                tr[i].update(1, 1, n, l, l+cot[i]-1, 1);
                l += cot[i];
            }
        }
    }
    print(n);
}
时间: 2024-10-04 01:15:17

[线段树] codeforces 558E. A Simple Task的相关文章

计数排序 + 线段树优化 --- Codeforces 558E : A Simple Task

E. A Simple Task Problem's Link: http://codeforces.com/problemset/problem/558/E Mean: 给定一个字符串,有q次操作,每次操作将(l,r)内的字符升序或降序排列,输出q次操作后的字符串. analyse: 基本思想是计数排序. 所谓计数排序,是对一个元素分布较集中的数字集群进行排序的算法,时间复杂度为O(n),但使用条件很苛刻.首先对n个数扫一遍,映射出每个数字出现的次数,然后再O(n)扫一遍处理出:对于数字ai,

Codeforces 558E A Simple Task (计数排序&amp;&amp;线段树优化)

题目链接:http://codeforces.com/contest/558/problem/E E. A Simple Task time limit per test5 seconds memory limit per test512 megabytes inputstandard input outputstandard output This task is very simple. Given a string S of length n and q queries each quer

codeforces 558E A Simple Task 线段树

题目链接 题意较为简单. 思路: 由于仅仅有26个字母,所以用26棵线段树维护就好了,比較easy. #include <iostream> #include <string> #include <vector> #include <cstring> #include <cstdio> #include <map> #include <queue> #include <algorithm> #include &

Codeforces 558E A Simple Task

Discription This task is very simple. Given a string S of length n and q queries each query is on the format i j k which means sort the substring consisting of the characters from i to j in non-decreasing order if k?=?1 or in non-increasing order if 

set+线段树 Codeforces Round #305 (Div. 2) D. Mike and Feet

题目传送门 1 /* 2 题意:对于长度为x的子序列,每个序列存放为最小值,输出长度为x的子序列的最大值 3 set+线段树:线段树每个结点存放长度为rt的最大值,更新:先升序排序,逐个添加到set中 4 查找左右相邻的位置,更新长度为r - l - 1的最大值,感觉线段树结构体封装不错! 5 详细解释:http://blog.csdn.net/u010660276/article/details/46045777 6 其实还有其他解法,先掌握这种:) 7 */ 8 #include <cstd

线段树 Codeforces Round #197 (Div. 2) D. Xenia and Bit Operations

题目传送门 1 /* 2 线段树的单点更新:有一个交叉更新,若rank=1,or:rank=0,xor 3 详细解释:http://www.xuebuyuan.com/1154895.html 4 */ 5 #include <cstdio> 6 #include <iostream> 7 #include <algorithm> 8 #include <cstring> 9 #include <string> 10 #include <c

【成端更新线段树模板】POJ3468-A Simple Problem with Integers

http://poj.org/problem?id=3468 _(:зゝ∠)_我又活着回来啦,前段时间太忙了写的题没时间扔上来,以后再说. [问题描述] 成段加某一个值,然后询问区间和. [思路] 讲一下pushdown和pushup出现的几个位置. pushup: (1)build的结尾,当叶子节点分别有对应的值后,它的父亲们就等于它们求和. (2)update的结尾,因为此时当前根的左右孩子已经更新了,故它也需要更新. pushdown(延迟标记): *pushdown会出现在一切要从当前结

线段树专题 POJ3468 A Simple Problem with Integers

题意:n个点.m个操作.两种操作类型.C X Y K 表示区间[x,y]上每一个点值加k.Q X Y 求区间[x,y]的和 分析:线段树区间求和,裸模板 注意:结果会超int,要用long long 表示,假设是在hust上交结果要用%I64d.poj的话则用%lld 代码: #include <iostream> #include <cstdio> #include <cstring> #include <queue> #include <algor

POJ 3468 (线段树 区间增减) A Simple Problem with Integers

这题WA了好久,一直以为是lld和I64d的问题,后来发现是自己的pushdown函数写错了,说到底还是因为自己对线段树理解得不好. 因为是懒惰标记,所以只有在区间分开的时候才会将标记往下传递.更新和查询都要pushdown. 1 #include <cstdio> 2 3 typedef long long LL; 4 5 const int maxn = 100000 + 10; 6 7 int n, m, qL, qR, v; 8 LL sum[maxn << 2], add