题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1166
题面:
1 10 1 2 3 4 5 6 7 8 9 10 Query 1 3 Add 3 6 Query 2 7 Sub 10 2 Add 6 3 Query 3 10 End
Case 1: 6 33 59
题目大意:
一共有n个兵营,每个兵营初始有ai个人。对应3种操作。
操作一:
Q A B 询问A到B共多少人。
操作二:
A X Y 给X兵营加Y个人。
操作三:
S X Y 给X兵营减去Y个人。
解题:
直接做,复杂度过高。用线段树维护,区间和。每种操作复杂度都为log(n)。
代码:
#include <iostream> #include <cstdio> #define maxn 50010 #define ls i<<1 #define rs (i<<1)|1 using namespace std; struct node { //左右边界,区间和 int l,r,sum; }stree[maxn<<2]; //4倍空间 //向上更新 void push_up(int i) { stree[i].sum=stree[ls].sum+stree[rs].sum; } //建树 void build(int i,int l,int r) { stree[i].l=l; stree[i].r=r; stree[i].sum=0; if(l==r) return; int mid=(l+r)>>1; build(ls,l,mid); build(rs,mid+1,r); //维护区间和 push_up(i); } //单点更新 void update(int i,int x,int v) { if(x==stree[i].l&&x==stree[i].r) { stree[i].sum+=v; return; } //根据相对位置,向下递归 int mid=(stree[i].l+stree[i].r)>>1; if(x<=mid)update(ls,x,v); else update(rs,x,v); push_up(i); } //区间查询 int query(int i,int l,int r) { //完全重合,返回区间值 if(l==stree[i].l&&stree[i].r==r) return stree[i].sum; int mid=(stree[i].l+stree[i].r)>>1; if(r<=mid) return query(ls,l,r); else if(l>mid) return query(rs,l,r); else return query(ls,l,mid)+query(rs,mid+1,r); } int main() { int t,n,tmp,x,v; char oper[10]; scanf("%d",&t); for(int i=1;i<=t;i++) { printf("Case %d:\n",i); scanf("%d",&n); //建树 build(1,1,n); //初值 for(int j=1;j<=n;j++) { scanf("%d",&tmp); update(1,j,tmp); } while(1) { scanf("%s",oper); if(oper[0]=='E') break; else if(oper[0]=='A') { scanf("%d%d",&x,&v); update(1,x,v); } else if(oper[0]=='S') { scanf("%d%d",&x,&v); update(1,x,-v); } else { scanf("%d%d",&x,&v); printf("%d\n",query(1,x,v)); } } } return 0; }