http://www.lydsy.com/JudgeOnline/problem.php?id=3211
这就是道傻逼题,但为了能完成我日更两篇的梦想,我就水一篇博客。。
对一段区间每个数开根号用线段树是打不了标记的,但是我们发现,一个数开根号很快就会变成1(或0),10^9开个5次基本上就稳定了。所以我们直接暴力下放标记到叶子,对于那些区间最大值<=1的,直接跳过即可。
对于线段树不能维护的标记,这种套路很常用的。它为什么叫势能分析线段树呢?我也不知道。(可能跟这个算法看上去好骗访问量有关吧)
#include
#include
#include
#include
#include
#include
#define maxn 100010
#define mid ((L + R) >> 1)
#define Lson (root << 1)
#define Rson (root << 1 | 1)
using namespace std;
typedef long long LL;
int n, m;
struct Tnode{
LL Max, sum;
} Tree[maxn<<2];
LL data[maxn];
void Build(int root, int L, int R){
if(L == R){
Tree[root].sum = Tree[root].Max = data[L];
return;
}
Build(Lson, L, mid);
Build(Rson, mid+1, R);
Tree[root].sum = Tree[Lson].sum + Tree[Rson].sum;
Tree[root].Max = max(Tree[Lson].Max, Tree[Rson].Max);
}
void Update(int root, int L, int R, int x, int y){
if(x > R || y < L) return;
if(x <= L && y >= R){
if(Tree[root].Max <= 1) return;
if(L == R){
Tree[root].sum = (LL)sqrt(Tree[root].sum);
Tree[root].Max = Tree[root].sum;
return;
}
}
Update(Lson, L, mid, x, y);
Update(Rson, mid+1, R, x, y);
Tree[root].Max = max(Tree[Lson].Max, Tree[Rson].Max);
Tree[root].sum = Tree[Lson].sum + Tree[Rson].sum;
}
LL Query(int root, int L, int R, int x, int y){
if(x > R || y < L) return 0LL;
if(x <= L && y >= R) return Tree[root].sum;
LL temp1 = Query(Lson, L, mid, x, y);
LL temp2 = Query(Rson, mid+1, R, x, y);
return temp1 + temp2;
}
int main(){
scanf("%d", &n);
for(int i = 1; i <= n; i++) scanf("%lld", &data[i]);
Build(1, 1, n);
scanf("%d", &m);
int op, l, r;
for(int i = 1; i <= m; i++){
scanf("%d%d%d", &op, &l, &r);
if(op == 1) printf("%lld\n", Query(1, 1, n, l, r));
else Update(1, 1, n, l, r);
}
return 0;
}