线段树题目,区间修改,区间内每个数x->sqrt(x),向下取整,数据不是太大,n=1e5,2^63开根号最大也就8,9次,完全可以暴力,中间可以判断这个区间是否满足 贡献=长度,及sum=r-l+1的话,就不必修改这个区间了。(注意输出格式,还是x和y的大小关系,不一定x小于y的,得判断一下)
代码:
#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <queue>
#include <vector>
#include <map>
using namespace std;
typedef long long ll;
typedef double db;
const int mod=1e9+7;
const int maxn=1e6+5;
const double eps=0.00000001;
struct D{
int l,r;
ll sum;
}tr[maxn*5];
ll a[maxn],v[maxn];
void build(int rt,int l,int r){
tr[rt].l=l,tr[rt].r=r;
if(l==r){
tr[rt].sum=a[l];
return;
}
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 l,int r){
if(tr[rt].l>=l&&tr[rt].r<=r&&tr[rt].r-tr[rt].l+1==tr[rt].sum) return;
if(tr[rt].l==tr[rt].r){
tr[rt].sum=sqrt(tr[rt].sum);
return;
}
if(tr[rt<<1].l>r||tr[rt<<1|1].r<l) return;
if(tr[rt<<1].r>=l) update(rt<<1,l,r);
if(tr[rt<<1|1].l<=r) update(rt<<1|1,l,r);
tr[rt].sum=tr[rt<<1].sum+tr[rt<<1|1].sum;
}
ll query(int rt,int l,int r){
if(tr[rt].l>=l&&tr[rt].r<=r){
return tr[rt].sum;
}
ll sum=0;
if(tr[rt<<1].l>r||tr[rt<<1|1].r<l) return 0;
if(tr[rt<<1].r>=l) sum+=query(rt<<1,l,r);
if(tr[rt<<1|1].l<=r) sum+=query(rt<<1|1,l,r);
return sum;
}
int main(){
int n,c=0;
while(scanf("%d",&n)!=EOF){
int p=0;
for(int i=1;i<=n;++i){
scanf("%lld",&a[i]);
}
build(1,1,n);
int m,s;
scanf("%d",&m);
while(m--){
scanf("%d",&s);
int x,y;
scanf("%d%d",&x,&y);
if(x>y) swap(x,y);
if(s==1){
v[++p]=query(1,x,y);
}else{
update(1,x,y);
}
}
printf("Case #%d:\n",++c);
for(int i=1;i<=p;++i) printf("%lld\n",v[i]);
puts("");
}
}