VJ Can you answer these queries ? (线段树区间修改+区间查询+剪枝)
原题
这题是一道很坑很坑的题!
题目给的是区间两个端点,并没说谁大谁小,所以在 change 之前要注意 l 和 r 大小,保证l <= r;
还有就是如果区间内的所有数都是 1 的话就不需要再修改了,否则再递归下去就会超时。所以要剪枝,当r(p)-l(p)+1==sum(p)时,就可以 return 掉了;
AC 代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll n,m;
ll a[1000005];
struct tree
{
ll l,r;
ll sum;
#define l(x) tree[x].l
#define r(x) tree[x].r
#define sum(x) tree[x].sum
}tree[4*200000+10];
void build(ll p,ll l,ll r)
{
l(p)=l,r(p)=r;
if(l==r)
{
sum(p)=a[l];
return ;
}
ll mid=l+r>>1;
build(2*p,l,mid);
build(2*p+1,mid+1,r);
sum(p)=sum(2*p)+sum(2*p+1);
}
void change(ll p,ll l,ll r)
{
if(sum(p)==r(p)-l(p)+1)
return ;
if(l(p)==r(p))
{
sum(p)=sqrt(sum(p));
return ;
}
ll mid=(l(p)+r(p)>>1);
if(l<=mid)
change(2*p,l,r);
if(r>mid)
change(2*p+1,l,r);
sum(p)=sum(2*p)+sum(2*p+1);
}
ll ask(ll p,ll l,ll r)
{
if(l<=l(p)&&r(p)<=r)
return sum(p);
ll mid=l(p)+r(p)>>1;
ll ans=0;
if(l<=mid)
ans+=ask(2*p,l,r);
if(mid<r)
ans+=ask(2*p+1,l,r);
return ans;
}
int main()
{
ll cot=1;
while(~scanf("%lld",&n))
{
printf("Case #%lld:\n",cot++);
for(ll i=1;i<=n;i++)
{
scanf("%lld",&a[i]);
}
build(1,1,n);
scanf("%lld",&m);
while(m--)
{
ll p,l,r;
scanf("%lld%lld%lld",&p,&l,&r);
ll x=l+r;
l=min(l,r);
r=x-l;
if(p==0)
change(1,l,r);
else if(p==1)
printf("%lld\n",ask(1,l,r));
}
printf("\n");
}
return 0;
}
戒骄戒躁,百炼成钢!