这道题最初思路是线段树维护每段区间被开平方的次数,然后最终query的时候取个循环,但是这样时间复杂度还是受不住
这道题的非线性导致了不小的麻烦,死板的想要依然遵循线段树延迟修改最后无路可走,所以,这道题的线段树很特殊,每次更新,都更新到最终的叶子节点为止(这也是看题解才收获的,还是需要训练量培养思路生成)
#include <iostream>
#include <algorithm>
#include <queue>
#include <string>
#include <vector>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <string>
#include <stack>
#include <map>
#include <set>
#include <deque>
using namespace std;
const int maxn= 1e5+5;
typedef unsigned long long LL;
struct Seg
{
int l, r;
LL sum;
}segTree[maxn<<2];
int n, m, op, x, y;
void Build(int x, int l, int r)
{
segTree[x].l= l;
segTree[x].r= r;
if (l== r){
scanf("%llu", &segTree[x].sum);
return;
}
int mid= (l+r)>>1;
Build(x<<1, l, mid);
Build(x<<1|1, mid+1, r);
segTree[x].sum= segTree[x<<1].sum+segTree[x<<1|1].sum;
}
void Update(int x, int l, int r)
{
if (l> r){
return;
}
if (segTree[x].sum== (LL)(segTree[x].r-segTree[x].l+1)){
return;
}
if (segTree[x].l== segTree[x].r){
segTree[x].sum= sqrt(1.0*segTree[x].sum);
return;
}
int mid= (segTree[x].l+segTree[x].r)>>1;
if (mid>= r){
Update(x<<1, l, r);
}
else if (mid< l){
Update(x<<1|1, l, r);
}
else{
Update(x<<1, l, mid);
Update(x<<1|1, mid+1, r);
}
segTree[x].sum= segTree[x<<1].sum+segTree[x<<1|1].sum;
}
LL Query(int x, int l, int r)
{
if (l> r){
return 0;
}
if (l== segTree[x].l && r== segTree[x].r){
return segTree[x].sum;
}
int mid= (segTree[x].l+segTree[x].r)>>1;
if (mid>= r){
return Query(x<<1, l, r);
}
else if (mid< l){
return Query(x<<1|1, l, r);
}
else{
return Query(x<<1, l, mid)+Query(x<<1|1, mid+1, r);
}
}
int main()
{
int kase= 0;
while (~scanf("%d", &n)){
Build(1, 1, n);
scanf("%d", &m);
printf("Case #%d:
", ++kase);
while (m--){
scanf("%d %d %d", &op, &x, &y);
if (x> y){
swap(x, y);
}
if (op){
printf("%llu
", Query(1, x, y));
}
else{
Update(1, x, y);
}
}
putchar('
');
}
}