码迷,mamicode.com
首页 > 其他好文 > 详细

CF558E A Simple Task

时间:2018-08-05 21:33:56      阅读:213      评论:0      收藏:0      [点我收藏+]

标签:using   权值线段树   修改   cpp   查询   rev   out   字母   switch   

题目大意

  给定一个长度不超过10^5的字符串(小写英文字母),和不超过5000个操作。每个操作 L R K 表示给区间[L,R]的字符串排序,K=1为升序,K=0为降序。最后输出最终的字符串。

题解

  我们做过luogu2828,那里我们无法对一段数字序列进行具体排序,那么这道题我们就要考虑其独有的特点。字母只有26个!所以我们对每个字母维护一个key值为下标,值为在下标范围内该字母出现次数的权值线段树即可,修改查询都很方便。

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;

const int MAX_N = 100010, MAX_ALPHA = 30;
int N;
int OrgData[MAX_N];
int ValPosCnt[MAX_ALPHA][MAX_N];

struct RangeTree
{
private:
    static const int MAX_NODE = MAX_N * 4;
    int Sum[MAX_NODE], Cover[MAX_NODE];
    
    void PushDown(int cur, int l, int r)
    {
        if(Cover[cur] != -1)
        {
            Cover[cur * 2] = Cover[cur * 2 + 1] = Cover[cur];
            int mid = (l + r) / 2;
            Sum[cur * 2] = (mid - l + 1) * Cover[cur];
            Sum[cur * 2 + 1] = (r - mid) * Cover[cur];
            Cover[cur] = -1;
        }
    }
    
    void PullUp(int cur)
    {
        Sum[cur] = Sum[cur * 2] + Sum[cur * 2 + 1];
    }
    
    void Init(int cur, int l, int r, int *a)
    {
        if(l == r)
        {
            Sum[cur] = a[l];
            return;
        }
        int mid = (l + r) / 2;
        Init(cur * 2, l, mid, a);
        Init(cur * 2 + 1, mid + 1, r, a);
        PullUp(cur);
    }
    
    int Query_Update(int cur, int curL, int curR, int askL, int askR, int cover)
    {
        if(askL <= curL && curR <= askR)
        {
            int ans = Sum[cur];
            Sum[cur] = (curR - curL + 1) * cover;
            Cover[cur] = cover;
            return ans;
        }
        PushDown(cur, curL, curR);
        int mid = (curL + curR) / 2, ans = 0;
        if(askL <= mid)
            ans += Query_Update(cur * 2, curL, mid, askL, askR, cover);
        if (askR > mid)
            ans += Query_Update(cur * 2 + 1, mid + 1, curR, askL, askR, cover);
        PullUp(cur);
        return ans;
    }
    
    void OutPut(int cur, int l, int r, int *a, int val)
    {
        if(Sum[cur] == r - l + 1)
        {
            for (int i = l; i <= r; i++)
                a[i] = val;
            return;
        }
        PushDown(cur, l, r);
        int mid = (l + r) / 2;
        if(Sum[cur * 2])
            OutPut(cur * 2, l, mid, a, val);
        if (Sum[cur * 2 + 1])
            OutPut(cur * 2 + 1, mid + 1, r, a, val); 
    }
    
public:
    RangeTree()
    {
        memset(Cover, -1, sizeof(Cover));
    }
    
    void Init(int *a)
    {
        Init(1, 1, N, a);
    }
    
    int Query_Update(int l, int r, int cover)
    {
        return Query_Update(1, 1, N, l, r, cover);
    }
    
    void OutPut(int *a, int val)
    {
        OutPut(1, 1, N, a, val);
    }
}g[MAX_ALPHA];

int main()
{
    int opCnt;
    scanf("%d%d\n", &N, &opCnt);
    for (int i = 1; i <= N; i++)
    {
        char c;
        scanf("%c", &c);
        OrgData[i] = c - ‘a‘ + 1;
    }
    for (int i = 1; i <= N; i++)
        ValPosCnt[OrgData[i]][i] += 1;
    for (int i = 1; i <= 26; i++)
        g[i].Init(ValPosCnt[i]);
    while(opCnt--)
    {
        int l, r, op;
        scanf("%d%d%d", &l, &r, &op);
        switch(op)
        {
            int prevR, prevL, num;
        case 1:
            prevR = l - 1;
            for (int i = 1; i <= 26; i++)
            {
                num = g[i].Query_Update(l, r, 0);
                if (num)
                {
                    g[i].Query_Update(prevR + 1, prevR + num, 1);
                    prevR = prevR + num;
                }
            }
            break;
        case 0:
            prevL = r + 1;
            for (int i = 1; i <= 26; i++)
            {
                num = g[i].Query_Update(l, r, 0);
                if (num)
                {
                    g[i].Query_Update(prevL - num, prevL - 1, 1);
                    prevL = prevL - num;
                }
            }
            break;
        }
    }
    static int ans[MAX_N];
    memset(ans, 0, sizeof(ans));
    for (int i = 1; i <= 26; i++)
        g[i].OutPut(ans, i);
    for (int i = 1; i <= N; i++)
        printf("%c", ans[i] + ‘a‘ - 1);
    printf("\n");
    return 0;
}

  

CF558E A Simple Task

标签:using   权值线段树   修改   cpp   查询   rev   out   字母   switch   

原文地址:https://www.cnblogs.com/headboy2002/p/9427022.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!