A - 一棵简单的线段树
人生已如此艰难,让我们活得轻松一点.
给你一个数组 A[1..n]A[1..n],初始时每个元素都为零.
我会请你帮我对数组完成一些操作.
第一种可能,我会给你两个数 pp 和 xx(1≤p≤n1≤p≤n),
请你帮我把数组的第 pp 个元素替换为 xx,
即 A[p]←xA[p]←x.
第二种可能,我会给你两个数 LL 和 RR(1≤L<R≤n1≤L<R≤n),
请你告诉我 A[L],A[L+1],…,A[R]A[L],A[L+1],…,A[R]
这几个数中去掉一个最大值和一个最小值后剩下的数的和是多少.
好了,现在锅都丢给你了,我可以活得轻松一点了.
Input输入第一行为一个整数 n (2≤n≤106)n (2≤n≤106),表示数组的大小.
第二行有一个整数 m (1≤m≤106)m (1≤m≤106),表示我需要你帮我完成的任务的个数.
第 33 到 m+2m+2 行每行有 3 个整数 o x yo x y.
如果 o=0o=0,代表我需要使 A[x]←yA[x]←y,
此时 1≤x≤n, |y|≤1091≤x≤n, |y|≤109.
如果 o=1o=1,代表我想知道 A[x],A[x+1],…,A[y]A[x],A[x+1],…,A[y]
去掉一个最大值和一个最小值后剩下的数的和为多少,
此时 1≤x<y≤n1≤x<y≤n.
对每个 o=1o=1 的任务,
输出只有一个整数的一行,
该整数表示区间 [x,y][x,y] 中的数
去掉一个最大值和一个最小值后剩下的数的和.
5 5 0 2 1 0 4 -2 1 1 5 0 1 5 1 1 4Sample Output
0 1
线段树的核心就是把一个区间分成两半再操作
三个数组,一个存区间和,一个存区间最大值,一个存区间最小值
坑点:区间和会爆int。。。
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int INF=0x7f7f7f7f;
long long btree[4000005];
int bmax[4000005];
int bmin[4000005];
int n,t;
int l,r;
int o,x,y;
void buildtree(int l,int r,int rt)//建树,rt为当前位置
{
if(l==r)
{
btree[rt]=0;
return ;
}
int mid=l+(r-l)/2;
buildtree(l,mid,rt*2);
buildtree(mid+1,r,rt*2+1);
btree[rt]=btree[rt*2]+btree[rt*2+1];
}
void buildmaxtree(int l,int r,int rt)
{
if(l==r)
{
bmax[rt]=0;
return ;
}
int mid=l+(r-l)/2;
buildmaxtree(l,mid,rt*2);
buildmaxtree(mid+1,r,rt*2+1);
bmax[rt]=max(bmax[rt*2],bmax[rt*2+1]);
}
void buildmintree(int l,int r,int rt)
{
if(l==r)
{
bmax[rt]=0;
return ;
}
int mid=l+(r-l)/2;
buildmintree(l,mid,rt*2);
buildmintree(mid+1,r,rt*2+1);
bmax[rt]=max(bmax[rt*2],bmax[rt*2+1]);
}
void modify(int l,int r,int rt,int p,int x)//单点修改值,p为值的下标,x为修改的目标值
{
if(l==r)
{
btree[rt]=x;
bmax[rt]=x;
bmin[rt]=x;
return ;
}
int mid=l+(r-l)/2;
if(p<=mid) modify(l,mid,rt*2,p,x);
else modify(mid+1,r,rt*2+1,p,x);
btree[rt]=btree[rt*2]+btree[rt*2+1];
bmax[rt]=max(bmax[rt*2],bmax[rt*2+1]);
bmin[rt]=min(bmin[rt*2],bmin[rt*2+1]);
}
long long findsum(int l,int r,int rt,int ll,int rr)//查询区间的和,ll区间左端,rr区间右端
{
if(ll<=l&&r<=rr) return btree[rt];
int mid=l+(r-l)/2;
long long ans=0;
if(ll<=mid) ans+=findsum(l,mid,rt*2,ll,rr);
if(rr>mid) ans+=findsum(mid+1,r,rt*2+1,ll,rr);
return ans;
}
int findmax(int l,int r,int rt,int ll,int rr)
{
if(ll<=l&&r<=rr) return bmax[rt];
int mid=l+(r-l)/2;
int ans=-INF;
if(ll<=mid) ans=max(ans,findmax(l,mid,rt*2,ll,rr));
if(rr>mid) ans=max(ans,findmax(mid+1,r,rt*2+1,ll,rr));
return ans;
}
int findmin(int l,int r,int rt,int ll,int rr)
{
if(ll<=l&&r<=rr) return bmin[rt];
int mid=l+(r-l)/2;
int ans=INF;
if(ll<=mid) ans=min(ans,findmin(l,mid,rt*2,ll,rr));
if(rr>mid) ans=min(ans,findmin(mid+1,r,rt*2+1,ll,rr));
return ans;
}
int main()
{
while(scanf("%d",&n)!=EOF)
{
memset(bmax,0,sizeof bmax);
memset(bmin,0,sizeof bmin);
memset(btree,0,sizeof btree);
scanf("%d",&t);
while(t--)
{
scanf("%d%d%d",&o,&x,&y);
if(o==0)
{
modify(1,n,1,x,y);
}
else
{
printf("%lld\n",findsum(1,n,1,x,y)-findmax(1,n,1,x,y)-findmin(1,n,1,x,y));
}
}
}
return 0;
}