一个序列,有两个操作:1、将一段区间的数开方; 2、求一段区间的和;
因为开平方不支持区间修改,只能进行单点修改,这样的话复杂度就会变成 O(n^2);如何优化?因为是开平方,所以10 ^ 9 的数最多进行6 - 7次左右就会变成 1 或 0,就没有必要在开方了,这里就打一个标记就可以了。不知道网上为什么那么多人要写并查集,可能会更快,还没想到。
/*
Author: JDD
PROG: bzoj3211.花神游历各国
DATE: 2015.11.04
*/
#include <cstdio>
#include <cmath>
using namespace std;
const int MAX_N = 100005;
struct node{
int l, r;
long long sum;
bool flag;
}a[MAX_N << 2];
int n, m, data[MAX_N];
inline int read()
{
int ret = 0; char c = getchar();
while(!(c >= '0' && c <= '9')) c = getchar();
while(c >= '0' && c <= '9') ret = ret * 10 + c - '0', c = getchar();
return ret;
}
void updata(int i)
{
int t1 = i << 1, t2 = t1 + 1;
a[i].sum = a[t1].sum + a[t2].sum;
a[i].flag = a[t1].flag & a[t2].flag;
}
void make_tree(int i, int l, int r)
{
a[i].l = l; a[i].r = r;
if(a[i].l == a[i].r){
a[i].sum = (long long)data[l];
if(a[i].sum == 1 || a[i].sum == 0) a[i].flag = 1;
return;
}
int mid = (a[i].l + a[i].r) >> 1, t1 = i << 1, t2 = t1 + 1;
make_tree(t1, l, mid); make_tree(t2, mid + 1, r);
updata(i);
}
void tree_sqrt(int i, int l, int r)
{
if(a[i].flag) return;
if(a[i].l == a[i].r){
a[i].sum = (long long)sqrt(a[i].sum);
if(a[i].sum == 1 || a[i].sum == 0) a[i].flag = 1;
return;
}
int mid = (a[i].l + a[i].r) >> 1, t1 = i << 1, t2 = t1 + 1;
if(r <= mid) tree_sqrt(t1, l, r);
else if(l > mid) tree_sqrt(t2, l, r);
else tree_sqrt(t1, l, mid), tree_sqrt(t2, mid + 1, r);
updata(i);
}
long long tree_calc(int i, int l, int r)
{
if(l > r) return 0;
if(a[i].l == l && a[i].r == r) return a[i].sum;
int mid = (a[i].l + a[i].r) >> 1, t1 = i << 1, t2 = t1 + 1;
if(r <= mid) return tree_calc(t1, l, r);
else if(l > mid) return tree_calc(t2, l, r);
else return tree_calc(t1, l, mid) + tree_calc(t2, mid + 1, r);
}
void init()
{
n = read();
for(int i = 1; i <= n; i ++) data[i] = read();
make_tree(1, 1, n);
}
void doit()
{
m = read();
while(m --){
int k, x, y; k = read(); x = read(); y = read();
if(k == 1) printf("%lld\n", tree_calc(1, x, y));
else tree_sqrt(1, x, y);
}
}
int main()
{
init(); doit();
return 0;
}