一个简单的任务 线段树

Posted ezoiHY

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了一个简单的任务 线段树相关的知识,希望对你有一定的参考价值。

这道题好猥琐啊啊啊啊啊啊

写了一个上午啊啊啊啊
没有在update里写pushup啊啊啊啊

题目大意:

给你一个字符串s,有q个操作
l r 1 :把sl..rsl..r按升序排序
l r 0 :把sl..rsl..r按降序排序

Solution:

我们考虑建26棵线段树,第i棵线段树的[x,y]表示在[x,y]中一共有多少个字母‘a‘+i-1
至于修改时我们可以以升序为例,从a至z按顺序往前丢,记得要清空区间
同理,降序反过来就是了

Code:

我们可以用sort啊啊,只不过会TLE

#pragma GCC optimize(3)
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
 
using namespace std;
 
int n,q;
char s[100001];
 
bool cmp(char a,char b){
    return a>b;
}
 
int main(){
    scanf("%d%d%s",&n,&q,s);
    for(int i=1;i<=q;i++){
        int l,r,x;
        scanf("%d%d%d",&l,&r,&x);
        if(x==1)sort(s+l-1,s+r);
        else sort(s+l-1,s+r,cmp);
        printf("%s\n",s);
    }
    printf("\n%s",s);
    return 0;
}

这里才是正解代码

#include<iostream>
#include<cstdio>
#include<cstring>

using namespace std;

char s[1000001];     
int n,m,sum[27][400001],lazy[27][400001];

inline int rd(){
    register int x=0,y=1;
    register char c=getchar();
    while(c>‘9‘ or c<‘0‘){
        if(c==‘-‘){
            y=-1;
        }
        c=getchar();
    }
    while(c>=‘0‘ and c<=‘9‘){
        x=(x<<1)+(x<<3)+(c^48);
        c=getchar();
    }
    return x*y;
}

inline void pushup(int o,int rt){
    sum[rt][o]=sum[rt][o<<1]+sum[rt][o<<1|1];
}

inline void pushdown(int o,int l,int r,int rt){
    if(lazy[rt][o]!=-1){
        int mid=(l+r)>>1;
        sum[rt][o]=lazy[rt][o]*(r-l+1);
        sum[rt][o<<1]=lazy[rt][o]*(mid-l+1);
        sum[rt][o<<1|1]=lazy[rt][o]*(r-mid);
        lazy[rt][o<<1]=lazy[rt][o<<1|1]=lazy[rt][o];
        lazy[rt][o]=-1;
    }
}

void build(int o,int l,int r){
    if(l==r){
        sum[s[l]-‘a‘+1][o]=1;
        return;
    }
    int mid=(l+r)>>1;
    build(o<<1,l,mid);
    build(o<<1|1,mid+1,r);
    for(int i=1;i<=26;i++)pushup(o,i);
}

inline int query(int o,int l,int r,int x,int y,int rt){
    if(x<=l and y>=r){
        return sum[rt][o];
    }
    pushdown(o,l,r,rt);
    int mid=(l+r)>>1,ret=0;
    if(x<=mid)ret+=query(o<<1,l,mid,x,y,rt);
    if(y>mid)ret+=query(o<<1|1,mid+1,r,x,y,rt);
    return ret;
}

inline void update(int o,int l,int r,int x,int y,int rt,int v){
    if(x<=l and y>=r){
        lazy[rt][o]=v;
        sum[rt][o]=v*(r-l+1);
        return;
    }
    pushdown(o,l,r,rt);
    int mid=(l+r)>>1;
    if(x<=mid)update(o<<1,l,mid,x,y,rt,v);
    if(y>mid)update(o<<1|1,mid+1,r,x,y,rt,v);
    pushup(o,rt);
}

void output(int o,int l,int r){
    if(l==r){
        for(int i=1;i<=26;i++){
            if(sum[i][o]){
                s[l]=‘a‘+i-1;
                break;
            }
        }
        return;
    }
    for(int i=1;i<=26;i++)pushdown(o,l,r,i);
    int mid=(l+r)>>1;
    output(o<<1,l,mid);
    output(o<<1|1,mid+1,r);
}

int main(){
    for(int i=1;i<=26;i++)memset(lazy[i],-1,sizeof(lazy[i]));
    n=rd(),m=rd();
    scanf("%s",s+1);
    build(1,1,n);
    while(m--){
        int x=rd(),y=rd();
        if(rd()){
            int tmp=x-1;
            for(int i=1;i<=26;i++){
                int cas=query(1,1,n,x,y,i);
                if(!cas)continue;
                update(1,1,n,x,y,i,0);
                update(1,1,n,tmp+1,tmp+cas,i,1);tmp=tmp+cas;
            }
        }else {
            int tmp=x-1;
            for(int i=26;i>=1;i--){
                int cas=query(1,1,n,x,y,i);
                if(!cas)continue;
                update(1,1,n,x,y,i,0);
                update(1,1,n,tmp+1,tmp+cas,i,1);tmp=tmp+cas;
            }
        }
    }
    output(1,1,n);
    printf("%s\n",s+1);
    return 0;
}

以上是关于一个简单的任务 线段树的主要内容,如果未能解决你的问题,请参考以下文章

敌兵布阵 (线段树简单模板题)

●洛谷P3168 [CQOI2015]任务查询系统

数据结构——线段树

P3168 [CQOI2015]任务查询系统

2017多校第8场 HDU 6133 Army Formations 线段树合并

线段树合并