题目链接: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 <iostream> #include <cstdio> #include <algorithm> #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; }