题意:给你 n 个数,m个询问(c,x,y)
c==0 把x,y区间的值变为原来的平方根(向下取整)
c==1 计算x,y区间的和。
利用1的开方永远为1剪枝。。
#include<cstdio>
#include<stdlib.h>
#include<string.h>
#include<string>
//#include<map>
#include<cmath>
#include<iostream>
#include <queue>
#include <stack>
#include<algorithm>
#include<set>
using namespace std;
#define inf 1e8
#define eps 1e-8
#define ll __int64
#define maxn 100001
#define mol 100007
struct node
{
int left,right;
int flag;//标记当前节点sum是否为1
ll sum;
}tree[maxn*3];
ll a[maxn];
void build(int id,int l,int r)
{
tree[id].left =l;tree[id].right =r;tree[id].sum =0;tree[id].flag=0;
if(l==r)
{
if(a[l]==1)
tree[id].flag=1;
tree[id].sum=a[l];
return;
}
int mid=(l+r)/2;
build(id*2,l,mid);
build(id*2+1,mid+1,r);
tree[id].sum=tree[id*2].sum+tree[id*2+1].sum;
if(tree[id*2].flag==1&&tree[id*2+1].flag==1)
tree[id].flag=1;
}
ll query(int id,int l,int r)
{
if(tree[id].flag==1) return r-l+1;//节点id区间都为1,返回区间长度
if(l==tree[id].left&&r ==tree[id].right )
return tree[id].sum ;
if(tree[id].left >r||tree[id].right<l) return 0;
int mid=(tree[id].left +tree[id].right )/2;
if(mid>=r)
return query(id*2,l,r);
else if(mid+1<=l) return query(id*2+1,l,r);
else return query(id*2,l,mid)+query(id*2+1,mid+1,r);
}
void update(int id ,int l,int r)
{
if(tree[id].flag==1)//节点id区间都为1,则不需要继续开方
return ;
if(tree[id].left==tree[id].right)
{
tree[id].sum=(ll)sqrt(tree[id].sum*1.0);
if(tree[id].sum==1)
tree[id].flag=1;
return ;
}
else
{
int mid=(tree[id].left+tree[id].right)/2;
if(mid>=r)
update(id*2,l,r);
else if(mid<l)
update(id*2+1,l,r);
else
{
update(id*2,l,mid);
update(id*2+1,mid+1,r);
}
}
tree[id].sum=tree[id*2].sum+tree[id*2+1].sum;
if(tree[id*2].flag==1&&tree[id*2+1].flag==1)
tree[id].flag=1;
}
int main()
{
int i,j;
int n,m,C=1;
while(~scanf("%d",&n))
{
for(i=1;i<=n;i++)
scanf("%I64d",&a[i]);
build(1,1,n);
scanf("%d",&m);
int c,x,y;
printf("Case #%d:\n",C++);
for(i=0;i<m;i++)
{
scanf("%d%d%d",&c,&x,&y);
if(x>y) swap(x,y);
if(c==0)
{
update(1,x,y);
}
else
{
printf("%I64d\n",query(1,x,y));
}
}
printf("\n");
}
return 0;
}