题目链接:https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=3238
题面:
题面PDF
题目大意:
从1到n编号,两种操作,操作一,S A X将A点的值修改为X。操作二,M A B,求区间AB的和。
解题:
线段树裸题,单点更新,区间求和。
代码:
#include
#include
#include
#define maxn 200010
using namespace std;
int sum[maxn<<2],resi[maxn],x;
//建树操作
int build(int le,int ri,int u)
{
//到单点了,更新
if(le==ri)
{
sum[u]=resi[le];
return sum[u];
}
else
{
//通过返回值,更新父亲节点
int mid=(le+ri)>>1;
sum[u]=build(le,mid,u<<1)+build(mid+1,ri,(u<<1)+1);
return sum[u];
}
}
//查询操作,le,ri当前查询的区间左右边界,lef,rig要查询的区间左右边界,u节点编号
int query(int le,int ri,int lef,int rig,int u)
{
//到达区间
if(le==lef&&ri==rig)
return sum[u];
int mid=(le+ri)>>1;
//在当前区间左半边
if(lef>=le&&rig<=mid)
return query(le,mid,lef,rig,u<<1);
//在当前区间右半边
else if(lef>=(mid+1)&&rig<=ri)
return query(mid+1,ri,lef,rig,(u<<1)+1);
//横跨左右区间
else
return query(le,mid,lef,mid,u<<1)+query(mid+1,ri,mid+1,rig,(u<<1)+1);
}
//更新操作
void update(int le,int ri,int u,int v)
{
//到达单点
if(le==ri)
{
sum[u]=v;
return;
}
else
{
int mid=(le+ri)>>1;
if(x<=mid)
update(le,mid,u<<1,v);
else
update(mid+1,ri,(u<<1)+1,v);
//更新父亲节点
sum[u]=sum[u<<1]+sum[(u<<1)+1];
}
}
int main()
{
char s[4];
int n,a,b,ans,cas=0;
while(scanf("%d",&n)&&n)
{
if(cas)printf("\nCase %d:\n",++cas);
else printf("Case %d:\n",++cas);
for(int i=1;i<=n;i++)
scanf("%d",&resi[i]);
build(1,n,1);
while(1)
{
scanf("%s",s);
if(s[0]=='M')
{
scanf("%d%d",&a,&b);
ans=query(1,n,a,b,1);
printf("%d\n",ans);
}
else if(s[0]=='S')
{
scanf("%d%d",&a,&b);
x=a;
update(1,n,1,b);
}
else break;
}
}
return 0;
}