数据结构专题之线段树的单点修改

题目

A - 一棵简单的线段树
Time Limit: 2000 MS     Memory Limit: 256 MB

人生已如此艰难,让我们活得轻松一点.

给你一个数组 A[1..n],初始时每个元素都为零.

我会请你帮我对数组完成一些操作.

第一种可能,我会给你两个数 p 和 x(1≤p≤n), 请你帮我把数组的第 p 个元素替换为 x, 即 A[p]←x.

第二种可能,我会给你两个数 L 和 R(1≤L<R≤n), 请你告诉我 A[L],A[L+1],…,A[R] 这几个数中去掉一个最大值和一个最小值后剩下的数的和是多少.

好了,现在锅都丢给你了,我可以活得轻松一点了.

Input
输入第一行为一个整数 n (2≤n≤106),表示数组的大小.

第二行有一个整数 m (1≤m≤106),表示我需要你帮我完成的任务的个数.

第 3 到 m+2 行每行有 3 个整数 o x y. 如果 o=0,代表我需要使 A[x]←y, 此时 1≤x≤n, |y|≤109. 如果 o=1,代表我想知道 A[x],A[x+1],…,A[y] 去掉一个最大值和一个最小值后剩下的数的和为多少, 此时 1≤x<y≤n.

Output
对每个 o=1 的任务, 输出只有一个整数的一行, 该整数表示区间 [x,y] 中的数 去掉一个最大值和一个最小值后剩下的数的和.

Sample input and output
Sample Input    Sample Output
5
5
0 2 1
0 4 -2
1 1 5
0 1 5
1 1 4
0
1
UESTC Online Judge

Copyright (C) 2012 - 2018 Ruins He(@ruinshe), Jianjin Fan(@pfctgeorge) and Yun Li(@mzry1992). Project home

Any Problem, Please Report On Issues Page.

这是线段树的模板
线段树无非是将区间对半分开然后处理
每一个节点记录的信息是L,R的信息的总和


#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <cstdlib>
#include <algorithm>
#include <vector>
#include <stack>
#include <set>
#include <map>
#include <queue>
#define scd(a) scanf("%d",&a)
#define scdd(a,b) scanf("%d%d",&a,&b)
#define scddd(a,b,c) scanf("%d%d%d",&a,&b,&c)

#define mset(var,val) memset(var,val,sizeof(var))

#define test(a) cout<<a<<endl
#define test2(a,b) cout<<a<<" "<<b<<endl

#define test3(a,b,c) cout<<a<<" "<<b<<" "<<c<<endl
const int N= 5e6+7;
const int mod =1e9+7;
using namespace std;
typedef long long ll;
ll qR,qL,p,v;
const int MAXN =5E6+7;
const int INF = 1e9+7;
struct segTree
{
        ll minv[MAXN];
        ll sumv[MAXN];
        ll maxv[MAXN];
        void update(ll o,ll L,ll R){
            ll M = L+(R-L)/2;
            if(L==R){
                minv[o]=v;
                maxv[o]=v;
                sumv[o]=v;
            }else{
                if(p<=M)update(o*2,L,M);else update(o*2+1,M+1,R);
                minv[o] = min(minv[o*2],minv[o*2+1]);
                maxv[o] = max(maxv[o*2],maxv[o*2+1]);
                sumv[o] = sumv[o*2]+sumv[o*2+1];
            }
        }
        ll queryMinv(ll o,ll L,ll R){
            ll M = L + (R-L)/2,ans = INF;
            if(qL<=L&&R<=qR)return minv[o];
            if(qL<=M){ans = min(ans,queryMinv(o*2,L,M));}
            if(M<qR) {ans = min(ans,queryMinv(o*2+1,M+1,R));}
            return ans;     
        }
        ll queryMax(ll o,ll L,ll R){
            ll M = L + (R-L)/2,ans = -INF;
            if(qL<=L&&R<=qR)return maxv[o];
            if(qL<=M){ans = max(ans,queryMax(o*2,L,M));};
            if(M<qR) {ans = max(ans,queryMax(o*2+1,M+1,R));}
            return ans;     
        };
        ll querySum(ll o,ll L,ll R){
            ll M = L + (R-L)/2,ans = 0;
            if(qL<=L&&R<=qR)return ans = sumv[o];
            if(qL<=M){ans= ans +querySum(o*2,L,M) ;};
            if(M<qR) {ans = ans+querySum(o*2+1,M+1,R);}
            return ans;     
        }
};
segTree tree;
void work(){
    ll n;
    scanf("%lld",&n);
    ll m;
    scanf("%lld",&m);
    int op;
    for(int i =0;i<m;i++){
        scanf("%d",&op);
        if(op==0){
            scanf("%lld%lld",&p,&v);
            tree.update(1,1,n);
        }else{
            scanf("%lld%lld",&qL,&qR);
            ll sum=tree.querySum(1,1,n);
            ll maxv = tree.queryMax(1,1,n);
            ll minv = tree.queryMinv(1,1,n);
            long long ans =sum -maxv-minv;
            // test3(sum,maxv,minv);
            printf("%lld\n",ans);
        }
    }
}
int main(){
    #ifdef local
        freopen("in.txt","r",stdin);
    #endif
    work();
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值