vj网址点击打开链接
原oj网址点击打开链接
这个题 是明显的是线段树 vj网址有中文 所以 在这里 就不多说了 代码上有我自己的见解 本人是个小菜鸡 要是有什么不对的地方 还需要各位大佬们的指教 orz 这道题 应该还是算作比较简单的 题 大家如果看不懂 可以上网上看看大牛们的大作,再来看本菜虾的博客(抛玉估计就不会有人看砖了把·~~~~~)
#include<stdio.h> #include<iostream> #include<string.h> #include<algorithm> #include<string> #include<math.h> using namespace std; const int nn=50500;// 数组需要开大一点 以防万一会爆炸 int sum[nn<<2];// 这是相当于nn*4 (不知道为啥线段树的代码非要这样写) char pp[15]; // 编译器明明就优化好了 在这样写 也不会优化时间啊~~~~ void upset(int re) { sum[re]=sum[re<<1]+sum[re<<1|1];// 这个是区间的总和 从下往上加 } void bulid(int l,int r,int re) // 开始建树 { if(l==r) //这样建树的好处 是既可以能够输入树 { //又能将sum准确的往上转递 scanf("%d",&sum[re]); return; } int mid=(l+r)>>1; bulid(l,mid,re<<1); bulid(mid+1,r,re<<1|1); upset(re);// 开始 传递 (递归的过程可以自己慢慢的画画 试着理解一下) } void update(int l,int c,int ll,int rr,int re) { if(rr==ll)// 这个是在树中开始查找sum的值 然后 进行加减 { sum[re]+=c; return; } //upset(re); int mid=(ll+rr)>>1; if(l>mid) update(l,c,mid+1,rr,re<<1|1); else update(l,c,ll,mid,re<<1); upset(re);//这一步是向上求 可以将结果 往上叠加(大概就是在回溯的过程中) } int query(int l,int r,int ll,int rr,int re) { if(ll>=l&&rr<=r) { return sum[re]; //这样是开始查找区间的值 查找成功 就开始传递 } int mid=(ll+rr)>>1; int ans=0; if(l<=mid) { ans+=query(l,r,ll,mid,re<<1); } if(r>mid) { ans+=query(l,r,mid+1,rr,re<<1|1); } return ans; } int main() { int t,qw=0,tt,ll,rr; scanf("%d",&t); while(t--) { qw++; scanf("%d",&tt); bulid(1,tt,1); // printf("1\n"); printf("Case %d:\n",qw); while(~scanf("%s",pp)) { if(strcmp(pp,"End")==0) break; scanf("%d%d",&ll,&rr); if(pp[0]=='A') { update(ll,rr,1,tt,1); } else if(pp[0]=='S') { update(ll,-rr,1,tt,1); } else { printf("%d\n",query(ll,rr,1,tt,1)); } } } return 0; }