这道题最坑的一点就是a,b大小关系不确定。。。另外如果区间内的所有数都是1就不必更新了,不然挨个更新叶子节点会TLE。。
改线段树的时候不是很敢改,但是看过标程发现还是要胆大一些。主要是区间更新,以前是一段更新,现在是以点更新;另外不需要用懒标记。不多说了,直接上AC代码:
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<iostream>
#include<algorithm>
#include<vector>
#include<map>
#include<set>
#include<stack>
#include<queue>
using namespace std;
#define ll long long
typedef pair<ll,ll>pp;
#define mkp make_pair
#define pb push_back
const ll INF=0x3f3f3f3f;
const ll MOD=1e9+7ll;
const ll MAX=100005;
int n,q;
ll ans;
struct node
{
ll l,r,w,f;
}tree[4*MAX];
void push_up(int k)
{
tree[k].w=tree[k<<1].w+tree[k<<1|1].w;
}
void build(int k,int l,int r)
{
tree[k].l=l,tree[k].r=r;
//tree[k].f=0;
if(tree[k].l==tree[k].r)
{ scanf("%lld",&tree[k].w); return; }
ll m=(tree[k].l+tree[k].r)>>1;
build(k<<1,l,m);
build(k<<1|1,m+1,r);
push_up(k);
}
void change_interval(int k,int a,int b,int y) //区间修改
{//如果区间内的所有数都是1就不必更新了,否则挨个更新叶子
if(tree[k].l==tree[k].r)
{
tree[k].w=sqrt(1.0*tree[k].w);
return;
}
/*if(tree[k].l>=a&&tree[k].r<=b)
{
tree[k].w+=(tree[k].r-tree[k].l+1)*y;
tree[k].f+=y;
return;
}*/
if(tree[k].l>=a&&tree[k].r<=b&&(tree[k].w==tree[k].r-tree[k].l+1))//区间内的所有数都是1
return;
//if(tree[k].f) down(k);
ll m=(tree[k].l+tree[k].r)>>1;
if(a<=m) change_interval(k<<1,a,b,y);
if(b>m) change_interval(k<<1|1,a,b,y);
push_up(k);
}
void ask_interval(int k,int a,int b) //区间查询
{
if(tree[k].l>=a&&tree[k].r<=b)
{ ans+=tree[k].w; return; }
//if(tree[k].f) down(k);
ll m=(tree[k].l+tree[k].r)>>1;
if(a<=m) ask_interval(k<<1,a,b);
if(b>m) ask_interval(k<<1|1,a,b);
}
int main()
{
int a,b;
int tt=0;
while(scanf("%d",&n)!=EOF)
{
build(1,1,n);
scanf("%d",&q);
int c;
tt++;printf("Case #%d:\n",tt);
while(q--)
{
scanf("%d%d%d",&c,&a,&b);
int tmp=min(a,b);//WA点!!!!!
b=max(a,b);
a=tmp;
if(c==0)//区间修改
{
change_interval(1,a,b,1);
}
else //区间查询
{
ans=0;
ask_interval(1,a,b);
printf("%lld\n",ans);
}
}
printf("\n");
}
return 0;
}