这是一个线段树的模板题,涉及到加减两种操作。
正好借这个题说一下遇到的集中奇葩情况。
线段树的知识可以自己百度下;
补充一点,后面那个输字符串和数字(eg Query 1 3)这里,不要把scanf写在if的前面,否则会出现Runtime Error错误,至今没弄明白为什么,希望后来者指点,谢谢。
先上代码:
#include<iostream>
#include<cstdio>
using namespace std;
typedef long long LL;
const int maxn = 50005;
LL val[maxn],ans;
struct Tree
{
int l,r;
int sum;
}tr[maxn<<2];
void build(int rt,int l,int r)
{
tr[rt].l = l;
tr[rt].r = r;
if(l==r)
tr[rt].sum=val[l];
else
{
int mid = (l+r)>>1;
build(rt<<1,l,mid);
build(rt<<1|1,mid+1,r);
tr[rt].sum = tr[rt<<1].sum+tr[rt<<1|1].sum;
}
}
void update(int rt,int x,int y)
{
tr[rt].sum+=y;
//添加停止条件
if(tr[rt].l==x&&tr[rt].r==x)
return ;
int mid=(tr[rt].l+tr[rt].r)>>1;
if(x>mid)
update(rt<<1|1,x,y);
else
update(rt<<1,x,y);
}
void query(int rt,int x,int y)
{
if(x<=tr[rt].l&&y>=tr[rt].r)
ans+=tr[rt].sum;
else
{
int mid = (tr[rt].l+tr[rt].r)>>1;
if(x>mid) //这个地方用的是存粹的>
query(rt<<1|1,x,y);
else if(y<=mid)
query(rt<<1,x,y);
else
{
query(rt<<1|1,x,y);
query(rt<<1,x,y);
}
}
}
int main()
{
LL T,F;
F=0;
cin>>T;
int x,y;
while(T--)
{
int N;
cin>>N;
for(int i=1;i<=N;i++)
scanf("%lld",&val[i]);
build(1,1,N);
string s;
while(cin>>s)
{
if(s=="End")
break;
else if(s=="Query")
{
scanf("%d%d",&x,&y);
ans = 0;
query(1,x,y);
printf("%lld\n",ans);
}
else if(s=="Add")
{
scanf("%d%d",&x,&y);
update(1,x,y);
}
else if(s=="Sub")
{
scanf("%d%d",&x,&y);
update(1,x,-y);
}
}
}
return 0;
}
奇葩情况分析:
1,到输字符串的时候,一个字符串也没输进去:
这是因为建树(build)时,这个else少了,自己思考为什么。
2.不进行更新操作(update)的能输进去,进行更新操作的输不进去:
这是因为在更新操作(update)中,没有及时终止程序的条件,不中止岂不是要死循环去了:
3.数据都能输进去,但是结果不正确,这是因为在查询操作(query)中,执行向右建树的判断条件多了个等于;
几个口诀吧:向右建树只大于,向左建树小于等于;
结果不对。
原因,看图吧:
4.这个问题放个图片理解下吧:
5.这个问题不严重,可能时粗心问题导致的,一定要细心,特别是写代码,就是别忘了建树,不然后面的 更新 、查询 从何谈起。