2个操作,一个是求区间和,一个是将区间内所有数开根号。
long long 开根号6.7次即可变成1,所以直接单点更新即可。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
using namespace std;
const int maxn = 1e5 + 5;
typedef long long ll;
struct node{
ll sum,m;
};
node seg[maxn << 2];
ll num[maxn];
int n,m;
void init(int l,int r,int rt)
{
if(l == r) {seg[rt].sum = num[l];seg[rt].m = num[l];return;}
int mid = (l + r) >> 1;
init(l, mid, rt << 1);
init(mid + 1, r, rt << 1 | 1);
seg[rt].sum = seg[rt << 1].sum + seg[rt << 1 | 1].sum;
seg[rt].m = max(seg[rt << 1].m,seg[rt << 1 | 1].m);
}
ll query(int ql,int qr,int l,int r,int rt)//区间和
{
if(ql <= l && r <= qr) return seg[rt].sum;
ll ans = 0;
int mid = (l + r) >> 1;
if(ql <= mid) ans += query(ql, qr, l, mid, rt << 1);
if(qr > mid) ans += query(ql, qr, mid + 1, r, rt << 1 | 1);
return ans;
}
void update_sec(int ql,int qr,int l,int r,int rt)
{
if(l == r) {seg[rt].m = sqrt(seg[rt].m);seg[rt].sum = sqrt(seg[rt].sum);return;}//!!!对区间进行单点更新
int mid = (l + r) >> 1;
if (ql <= mid && seg[rt << 1].m > 1) update_sec(ql, qr, l, mid, rt << 1);//seg[].max <= 1区间内全为1则不用更新
if(mid < qr && seg[rt << 1 | 1].m > 1) update_sec(ql, qr, mid + 1, r, rt << 1 | 1);
seg[rt].sum = seg[rt << 1].sum + seg[rt << 1 | 1].sum;
seg[rt].m = max(seg[rt << 1].m,seg[rt << 1 | 1].m);
}
int main()
{
int cn = 0;
while (scanf("%d",&n) != EOF) {
printf("Case #%d:\n",++cn);
memset(seg, 0, sizeof(seg));
memset(num, 0, sizeof(num));
for (int i = 1; i <= n; i ++) {
scanf("%lld",&num[i]);
}
init(1, n, 1);
scanf("%d",&m);
int t,x,y;
for (int i = 0; i < m; i ++) {
scanf("%d%d%d",&t,&x,&y);//t = 0 更新,t = 1查询
if(x > y) swap(x, y);
if(t == 0) { update_sec(x, y, 1, n, 1);}
else{ if(x <= y) printf("%lld\n",query(x, y, 1, n, 1));}
}
printf("\n");
}
return 0;
}