BZOJ 3211: 花神游历各国(势能分析线段树)

题目在这里

http://www.lydsy.com/JudgeOnline/problem.php?id=3211


题解

这就是道傻逼题,但为了能完成我日更两篇的梦想,我就水一篇博客。。

对一段区间每个数开根号用线段树是打不了标记的,但是我们发现,一个数开根号很快就会变成1(或0),10^9开个5次基本上就稳定了。所以我们直接暴力下放标记到叶子,对于那些区间最大值<=1的,直接跳过即可。

对于线段树不能维护的标记,这种套路很常用的。它为什么叫势能分析线段树呢?我也不知道。(可能跟这个算法看上去好骗访问量有关吧)


代码

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <cstring>
#include <cmath>
#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;
} 

这里写图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值