codevs 4927 线段树练习5

 时间限制: 1 s
 空间限制: 128000 KB
 题目等级 : 黄金 Gold
 
 
题目描述 Description

有n个数和5种操作

add a b c:把区间[a,b]内的所有数都增加c

set a b c:把区间[a,b]内的所有数都设为c

sum a b:查询区间[a,b]的区间和

max a b:查询区间[a,b]的最大值

min a b:查询区间[a,b]的最小值

输入描述 Input Description

第一行两个整数n,m,第二行n个整数表示这n个数的初始值

接下来m行操作,同题目描述

输出描述 Output Description

对于所有的sum、max、min询问,一行输出一个答案

样例输入 Sample Input

10 6

3 9 2 8 1 7 5 0 4 6

add 4 9 4

set 2 6 2

add 3 8 2

sum 2 10

max 1 7

min 3 6

 

样例输出 Sample Output

49

11

4

 

数据范围及提示 Data Size & Hint

10%:1<n,m<=10

30%:1<n,m<=10000

100%:1<n,m<=100000

保证中间结果在long long(C/C++)、int64(pascal)范围内

 

PS:由于数据6出错导致某些人只有90分,已于2016.5.13修正。

出题人在此对两位90分的用户表示诚挚的歉意

分类标签 Tags 点此展开 

 思路:区间赋值和区间加法综合操作。

先赋值,后加法。

注意:有一个全部赋值为0的情况。

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define MAXN 100001
using namespace std;
int n,m;
struct nond{
    int l,r;
    long long sum,max,min;
    long long flag1,flag2;
}tree[MAXN*4];
void up(int now){
    tree[now].sum=tree[now*2].sum+tree[now*2+1].sum;
    tree[now].min=min(tree[now*2].min,tree[now*2+1].min);
    tree[now].max=max(tree[now*2].max,tree[now*2+1].max);
}
void build(int now,int l,int r){
    tree[now].l=l;tree[now].r=r;
    tree[now].flag2=-1;
    if(tree[now].l==tree[now].r){
        scanf("%lld",&tree[now].sum);
        tree[now].min=tree[now].max=tree[now].sum;
        return ;
    }
    int mid=(tree[now].l+tree[now].r)/2;
    build(now*2,l,mid);
    build(now*2+1,mid+1,r);
    up(now);
}
void down(int now){
    if(tree[now].flag2!=-1){
        tree[now*2].flag2=tree[now].flag2;
        tree[now*2+1].flag2=tree[now].flag2;
        tree[now*2].flag1=tree[now*2+1].flag1=0;
        tree[now*2].min=tree[now*2].max=tree[now].flag2;
        tree[now*2+1].min=tree[now*2+1].max=tree[now].flag2;
        tree[now*2].sum=(tree[now*2].r-tree[now*2].l+1)*tree[now].flag2;
        tree[now*2+1].sum=(tree[now*2+1].r-tree[now*2+1].l+1)*tree[now].flag2;
        tree[now].flag2=-1;
    }
    if(tree[now].flag1){
        tree[now*2].flag1+=tree[now].flag1;
        tree[now*2+1].flag1+=tree[now].flag1;
        tree[now*2].min+=tree[now].flag1;
        tree[now*2+1].min+=tree[now].flag1;
        tree[now*2].max+=tree[now].flag1;
        tree[now*2+1].max+=tree[now].flag1;
        tree[now*2].sum+=(tree[now*2].r-tree[now*2].l+1)*tree[now].flag1;
        tree[now*2+1].sum+=(tree[now*2+1].r-tree[now*2+1].l+1)*tree[now].flag1;
        tree[now].flag1=0;
    } 
}
void changeadd(int now,int l,int r,long long k){
    if(tree[now].l==l&&tree[now].r==r){
        tree[now].sum+=(tree[now].r-tree[now].l+1)*k;
        tree[now].min+=k;tree[now].max+=k;tree[now].flag1+=k;
        return ;
    }
    if(tree[now].flag1||tree[now].flag2!=-1)    down(now);
    int mid=(tree[now].l+tree[now].r)/2;
    if(r<=mid)    changeadd(now*2,l,r,k);
    else if(l>mid)    changeadd(now*2+1,l,r,k);
    else { changeadd(now*2,l,mid,k);changeadd(now*2+1,mid+1,r,k); }
    up(now);
}
void changeset(int now,int l,int r,long long k){
    if(tree[now].l==l&&tree[now].r==r){
        tree[now].min=k;tree[now].max=k;
        tree[now].flag1=0;tree[now].flag2=k;
        tree[now].sum=(tree[now].r-tree[now].l+1)*k;
        return ;
    }
    if(tree[now].flag1||tree[now].flag2!=-1)    down(now);
    int mid=(tree[now].l+tree[now].r)/2;
    if(r<=mid)    changeset(now*2,l,r,k);
    else if(l>mid)    changeset(now*2+1,l,r,k);
    else { changeset(now*2,l,mid,k);changeset(now*2+1,mid+1,r,k); }
    up(now);
}
long long querysum(int now,int l,int r){
    if(tree[now].l==l&&tree[now].r==r)
        return tree[now].sum;
    if(tree[now].flag1||tree[now].flag2!=-1)    down(now);
    int mid=(tree[now].l+tree[now].r)/2;
    if(r<=mid)    return querysum(now*2,l,r);
    else if(l>mid)    return querysum(now*2+1,l,r);
    else return querysum(now*2,l,mid)+querysum(now*2+1,mid+1,r); 
}
long long querymax(int now,int l,int r){
    if(tree[now].l==l&&tree[now].r==r)
        return tree[now].max;
    if(tree[now].flag1||tree[now].flag2!=-1)    down(now);
    int mid=(tree[now].l+tree[now].r)/2;
    if(r<=mid)    return querymax(now*2,l,r);
    else if(l>mid)    return querymax(now*2+1,l,r);
    else return max(querymax(now*2,l,mid),querymax(now*2+1,mid+1,r)); 
}
long long querymin(int now,int l,int r){
    if(tree[now].l==l&&tree[now].r==r)
        return tree[now].min;
    if(tree[now].flag1||tree[now].flag2!=-1)    down(now);
    int mid=(tree[now].l+tree[now].r)/2;
    if(r<=mid)    return querymin(now*2,l,r);
    else if(l>mid)    return querymin(now*2+1,l,r);
    else return min(querymin(now*2,l,mid),querymin(now*2+1,mid+1,r)); 
}
int main(){
    scanf("%d%d",&n,&m);
    build(1,1,n);
    for(int i=1;i<=m;i++){
        char opt[10];int a,b;long long c;
        cin>>opt;scanf("%d%d",&a,&b);
        if(opt[0]=='a'){
            scanf("%lld",&c);
            changeadd(1,a,b,c);
        }
        else if(opt[0]=='s'&&opt[1]=='e'){
            scanf("%lld",&c);
            changeset(1,a,b,c);
        }
        else if(opt[0]=='s'&&opt[1]=='u')
            printf("%lld\n",querysum(1,a,b));
        else if(opt[0]=='m'&&opt[1]=='a')
            printf("%lld\n",querymax(1,a,b));
        else printf("%lld\n",querymin(1,a,b));
    }
}

 

转载于:https://www.cnblogs.com/cangT-Tlan/p/8537326.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值