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;
}