https://cn.vjudge.net/problem/HDU-4027
给n个数
然后两种操作
0操作 把【l,r】的数都开根(向下取整)
1操作 输出【l,r】的区间和
因为这是每个数开根 而不是加上 所以结点没法直接更新
不同于懒标记 懒标记是把当前结点标记了,同时也更新当前结点的信息 然后直接返回
注意懒标记下面的数据还没更新的!! 但是没关系 如果下次访问到 pushdown会帮我们把上面的懒标记传下去
从而更新 这就是所谓的“懒” 用到时才行动 所以高效
这题解决:全都走到叶节点加
直接更新叶节点 然后靠pushup把上面修正
然而TLE
还需要一个剪枝 我们知道开根 2^63
开一次2^31 2^15 2^7 2^3 2^1 2^0
也就那么6 、7 次
1开根还是1 就没必要再去开根了
秒: 如果区间和 比如【2,7】的区间和 若是7-2+1=6 这里面就有6个数
这说明 从rt开始 叶节点都是1 那既然是1 就不用再下去 开根还是1
如 1--3 3
1--2 3 对应的值 2 1
1 2 1 1
所以直接返回 当前结点的这一子树 无需做无用功
#include<iostream>
#include<cstring>
#include<cmath>
#include<string>
#include<map>
#include<vector>
#include<set>
#include<queue>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<functional>
using namespace std;
#define inf 0x3f3f3f3f
#define pi acos(-1.0)
#define LL long long
#define lson l, m, rt << 1
#define rson m + 1, r, rt << 1 | 1
//#define mp make_pair
#define pb push_back
#define ULL unsigned LL
#define mem(a, b) memset(a, b, sizeof(a))
#define ios ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)
//#define fopen freopen("in.txt", "r", stdin);freopen("out.txt", "w", stout);
const int maxn = 1e5 + 100;
LL sum[4 * maxn];
//int lazy[4* maxn];
inline void pushup(int rt){
sum[rt] = sum[rt << 1] + sum[rt << 1 | 1];
}
void build(int l, int r, int rt){
if (l == r){
scanf("%lld", &sum[rt]);
return;
}
int m = l + (r - l) / 2;
build(lson);
build(rson);
pushup(rt);
}
void update(int L, int R, int l, int r, int rt){
//因为这是每个数开根 而不是加上 所以结点没法直接更新
//解决:全都走到叶节点加
//直接更新叶节点 然后考pushup把上面修正
if (l == r){
sum[rt] = sqrt(sum[rt] * 1.0);//转成long long 相当于向下取整
return;
}
//如果区间和 比如【2,7】的区间和 若是7-2+1=6 这里面就有6个数
//这说明 从rt开始 叶节点都是1 那既然是1 就不用再下去 开根还是1
if (L <= l && R >= r && sum[rt] == r - l + 1)
return;
int m = l + (r - l ) / 2;
//pushdown(rt, m - l + 1, r - m);
if (m >= L)
update(L, R, lson);
if (m + 1<= R)
update(L, R, rson);
pushup(rt);
}
LL query(int L, int R, int l, int r, int rt){
if (l >= L && r <= R){
return sum[rt];
}
LL res = 0;
int m = l + (r - l ) / 2;
if (m >= L)
res += query(L, R, lson);
if (m + 1 <= R)
res += query(L, R, rson);
return res;
}
int main(){
int n;
int cas = 1;
while (~scanf("%d", &n)){
mem(sum, 0);
printf("Case #%d:\n", cas++);
build(1, n, 1);
int m;
scanf("%d", &m);
int a, b, c;
while (m--){
scanf("%d%d%d", &a, &b, &c);
int f = min(b, c), s = max(b, c);
if (a == 0)
update(f, s, 1, n, 1);
else if (a == 1)
printf("%lld\n", query(f, s, 1, n, 1));
}
puts("");
}
return 0;
}

本文探讨了在处理数组元素开方操作时,如何利用线段树进行区间更新和查询的优化策略。针对每次开方操作后数值变化不大的特点,提出了一种剪枝策略,避免不必要的叶节点遍历,显著提高了算法效率。
489

被折叠的 条评论
为什么被折叠?



