hdu4027 Can you answer these queries? 线段树

题目链接在这里

题目描述:

有n个数,m次操作,每次操作给出x y z三个数,规则如下:

若x == 0,则将[ y ,  z ]区间的数开平方根(向下取整)

若x == 1,则将[ y , z ]区间的和求出来。

思路分析:

这是个并查集问题,每次更新的时候将子节点开平方就可以了。

但是值得注意的是,当值已经为1的时候,再开平方根已经没有意义了,所以优化一下,若某个节点值 == 最右下标 - 最左下标 + 1,即它的孩子的长度的话,就不用再往下进行了。

另外一个比较坑的点是,y有可能大于z,所以一定要判断一下大小。

代码如下:

#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <iostream>
#define rep(i, n) for(int i = 0; i < n; ++i)
#define clr(x) memset(x, 0, sizeof(x))
#define rl (rt << 1)
#define rr (rt << 1 | 1)
#define ll long long
using namespace std;
const int MaxN = 2e5 + 10;

struct Node{
    int l, r, mid;
    ll val;
}tree[MaxN << 2];

int n, q;
ll ans;

void build(int l, int r, int rt){
    tree[rt].l = l;
    tree[rt].r = r;
    tree[rt].mid = (l + r) >> 1;
    if(l == r){
        scanf("%lld", &tree[rt].val);
        return;
    }
    build(l, tree[rt].mid, rl);
    build(tree[rt].mid + 1, r, rr);
    tree[rt].val = tree[rl].val + tree[rr].val;
}

void update(int l, int r, int rt){
    //printf("l:%d, r:%d, rt:%d\n", l, r, rt);
    if(tree[rt].val == tree[rt].r - tree[rt].l + 1) return;
    if(tree[rt].l == tree[rt].r){
        //printf("in, l:%d\n", l);
        tree[rt].val = sqrt(tree[rt].val);
        return;
    }
    if(r <= tree[rt].mid)
        update(l, r, rl);
    else if(l > tree[rt].mid)
        update(l, r, rr);
    else{
        update(l, tree[rt].mid, rl);
        update(tree[rt].mid + 1, r, rr);
    }
    tree[rt].val = tree[rl].val + tree[rr].val;
    //printf("l:%d, r:%d, val:%lld, rt:%d\n", tree[rt].l, tree[rt].r, tree[rt].val, rt);
}

void query(int l, int r, int rt){
    if(l <= tree[rt].l && tree[rt].r <= r){
        //printf("l:%d, r:%d, val:%lld\n", tree[rt].l, tree[rt].r, tree[rt].val);
        ans += tree[rt].val;
        return;
    }
    if(r <= tree[rt].mid)
        query(l, r, rl);
    else if(l > tree[rt].mid)
        query(l, r, rr);
    else{
        query(l, tree[rt].mid, rl);
        query(tree[rt].mid + 1, r, rr);
    }
}

int main(){
    int Case = 1;
    while(~scanf("%d", &n)){
        build(1, n, 1);
        scanf("%d", &q);
        int x, y, z;
        printf("Case #%d:\n", Case++);
        while(q--){
            scanf("%d %d %d", &x, &y, &z);
            if(y > z){
                y ^= z;
                z ^= y;
                y ^= z;
            }
            if(x){
                ans = 0;
                query(y, z, 1);
                printf("%lld\n", ans);
            }
            else{
                update(y, z, 1);
            }
        }
        putchar('\n');
    }
    return 0;
}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值