题意 : 给你N个数以及M个操作,操作分两类,第一种输入 "0 l r" 表示将区间[l,r]里的每个数都开根号。第二种输入"1 l r",表示查询区间[l,r]里所有数的和。

分析 : 不难想到用线段树,但是这里的线段树开根操作的更新很明显不能跟加减操作那样子通过Lazy Tag来实现,那么最笨的方法就是一直更新到叶子节点,不过这也就失去了线段树的高效性,每一次操作都更新到叶子节点的话会超时,此时来想想有没有什么规律可以减少操作的复杂度,细想就会发现在有限次的开根之后所有的数都会变成1,这里能给出的最大的数是263这个数被开根七次之后就会变成1,那么如果需要更新的某一段的值已经被开根了7次或7次以上那么就无需再向下更新,也就是每个叶子节点最多更新7次。普通的线段树操作就不叙述了,这里说说判断是否已经开根七次的方法。

①多开辟一个标记数组来记录开根信息,比如给区间(l, r)开根,那么就把被(l, r)包裹住的子区间对应的标记+1,同样的,如果下一次碰到某一个子区间的标记已经>=7了那么就直接return无需向下更新。

#include<bits/stdc++.h>
#define LL long long
#define lson l,   m, rt<<1
#define rson m+1, r, rt<<1|1
using namespace std;
 + ;
LL sumv[maxn<<];
];
int N, M;

inline void build(int l, int r, int rt)
{
    if(l == r){
        scanf("%I64d", &sumv[rt]);
        return ;
    }
    ;
    build(lson);
    build(rson);
    sumv[rt] = sumv[rt<<] + sumv[rt<<|];
}

inline void update(int L, int R, int l, int r, int rt)
{
    ){///先判断是否是被查询区间包裹的子区间,再判断是否需要继续向下更新
        sumv[rt] = r - l + ;
        return ;
    }
    if(L <= l && r <= R) sq[rt]++;///注意什么时候需要+1
    if(l == r){
        ///sq[rt]++ 之前因为逻辑疏忽,我在这里也+1操作了,WA了很多次静下来思考才发现
        sumv[rt] = (LL)sqrt(sumv[rt]);
        return ;
    }
    ;
    if(L <= m) update(L, R, lson);
    if(R >  m) update(L, R, rson);
    sumv[rt] = sumv[rt<<] + sumv[rt<<|];
}

LL query(int L, int R, int l, int r, int rt)
{
    if(L <= l && r <= R) return sumv[rt];
    LL ret = ;
    ;
    if(L <= m) ret += query(L, R, lson);
    if(R >  m) ret += query(L, R, rson);
    return ret;
}

int main(void)
{
    ;
    while(~scanf("%d", &N)){
        memset(sumv, , sizeof(sumv));
        memset(sq, , sizeof(sq));

        build(, N, );
        scanf("%d", &M);
        printf("Case #%d:\n", Case++);
        while(M--){
            int command, L, R;
            scanf("%d%d%d", &command, &L, &R);
            if(L > R) swap(L, R);
            , N, );
            , N, ));
        }
        puts("");
    }
    ;
}

②实际上有个更简便的方法,就是最后被开7次根及以上的区间和都会变成区间长度,那么我们只要每一次都判断被(l, r)包裹住的子区间的和是否等于区间长度就能判断是否需要再继续更新下去了。

#include<bits/stdc++.h>
#define LL long long
#define lson l,   m, rt<<1
#define rson m+1, r, rt<<1|1
using namespace std;
 + ;
LL sumv[maxn<<];
int N, M;

inline void build(int l, int r, int rt)
{
    if(l == r){
        scanf("%I64d", &sumv[rt]);
        return ;
    }
    ;
    build(lson);
    build(rson);
    sumv[rt] = sumv[rt<<] + sumv[rt<<|];
}

inline void update(int L, int R, int l, int r, int rt)
{
    ) return ;
    if(l == r){
        sumv[rt] = (LL)sqrt(sumv[rt]);
        return ;
    }
    ;
    if(L <= m) update(L, R, lson);
    if(R >  m) update(L, R, rson);
    sumv[rt] = sumv[rt<<] + sumv[rt<<|];
}

LL query(int L, int R, int l, int r, int rt)
{
    if(L <= l && r <= R){
        return sumv[rt];
    }
    LL ret = ;
    ;
    if(L <= m) ret += query(L, R, lson);
    if(R >  m) ret += query(L, R, rson);
    return ret;
}

int main(void)
{
    ;
    while(~scanf("%d", &N)){
        memset(sumv, , sizeof(sumv));

        build(, N, );
        scanf("%d", &M);
        printf("Case #%d:\n", Case++);
        while(M--){
            int command, L, R;
            scanf("%d%d%d", &command, &L, &R);
            if(L > R) swap(L, R);
            , N, );
            , N, ));
        }
        puts("");
    }
    ;
}

瞎 :

①更新到叶子节点的操作实际无需在main里面使用一个for循环,只要将update里面赋值的语句将原来的if(L <= l && r <= R)改成if(l == r)即可

②以后遇到类似开根的削减操作,可以考虑被削减多次之后变成的固定值会不会是解题的一个突破口

③在实现想法的时候需要认真思考,逻辑千万不能乱,否则调试起来相当困难,比如第一种判断方法下自己就写错了很多次,这还不要紧,关键是会怀疑一些没有必要怀疑的地方,冷静分析最重要,如果真的已经很乱了,不妨将代码删除,再来一遍!

HDU 4027 Can you answer these queries? (线段树成段更新 && 开根操作 && 规律)的更多相关文章

  1. HDU 4027 Can you answer these queries?(线段树,区间更新,区间查询)

    题目 线段树 简单题意: 区间(单点?)更新,区间求和  更新是区间内的数开根号并向下取整 这道题不用延迟操作 //注意: //1:查询时的区间端点可能前面的比后面的大: //2:优化:因为每次更新都 ...

  2. hdu 4027 Can you answer these queries? 线段树区间开根号,区间求和

    Can you answer these queries? Time Limit: 1 Sec  Memory Limit: 256 MB 题目连接 http://acm.hdu.edu.cn/sho ...

  3. HDU 4027 Can you answer these queries? (线段树区间修改查询)

    描述 A lot of battleships of evil are arranged in a line before the battle. Our commander decides to u ...

  4. hdu 4027 Can you answer these queries? 线段树

    线段树+剪枝优化!!! 代码如下: #include<iostream> #include<stdio.h> #include<algorithm> #includ ...

  5. hdu 4747【线段树-成段更新】.cpp

    题意: 给出一个有n个数的数列,并定义mex(l, r)表示数列中第l个元素到第r个元素中第一个没有出现的最小非负整数. 求出这个数列中所有mex的值. 思路: 可以看出对于一个数列,mex(r, r ...

  6. HDU 3577 Fast Arrangement ( 线段树 成段更新 区间最值 区间最大覆盖次数 )

    线段树成段更新+区间最值. 注意某人的乘车区间是[a, b-1],因为他在b站就下车了. #include <cstdio> #include <cstring> #inclu ...

  7. ACM: Copying Data 线段树-成段更新-解题报告

    Copying Data Time Limit:2000MS Memory Limit:262144KB 64bit IO Format:%I64d & %I64u Description W ...

  8. POJ3468_A Simple Problem with Integers(线段树/成段更新)

    解题报告 题意: 略 思路: 线段树成段更新,区间求和. #include <iostream> #include <cstring> #include <cstdio& ...

  9. Codeforces Round #149 (Div. 2) E. XOR on Segment (线段树成段更新+二进制)

    题目链接:http://codeforces.com/problemset/problem/242/E 给你n个数,m个操作,操作1是查询l到r之间的和,操作2是将l到r之间的每个数xor与x. 这题 ...

随机推荐

  1. Elasticsearch入门(二)

    基础概念 Elasticsearch有几个核心概念,从一开始理解这些概念会对整个学习过程有莫大的帮助. 接近实时(NRT) Elasticsearch是一个接近实时的搜索平台.这意味着,从索引一个文档 ...

  2. 【ABAP系列】SAP 面试 ABAPer的一些感想

    公众号:SAP Technical 本文作者:matinal 原文出处:http://www.cnblogs.com/SAPmatinal/ 原文链接:[ABAP系列]SAP 面试 ABAPer的一些 ...

  3. idea的掌握

    1:idea的界面了解(一般都会勾选这两项,编码比较方便) 2: 如何配置sdk(jdk,最后一个生成的是.class文件的位置) 3: 如何单个项目配置和全局配置 4:如何配置项目的jdk编译版本和 ...

  4. 成功安装 Visio 2016 和 Office 2016 的64位版本~~

    .XML是个很  的东西!!! 折腾了一下 Visio 2016_x64 和 Office 2016_x64,功夫不负! 首先,选对配置工具很重要. 之前总是失败是因为在官网下载的配置工具是给2019 ...

  5. [19/10/14-星期一] Python中的对象和类

    一.面向对象 ## 什么是对象? - 对象是内存中专门用来存储数据的一块区域. - 对象中可以存放各种数据(比如:数字.布尔值.代码) - 对象由三部分组成: 1.对象的标识(id) 2.对象的类型( ...

  6. Larkin’s NOI

    Larkin’s NOI Problem Description Larkin has been to Yantai to take part in NOI 2010!众所周知(do you know ...

  7. markdown编辑器学习

    markdown是一块文本编辑器,属于纯文本文件,可以使用任何编辑器打开.对于写作来说是一个好帮手,它的好处有很多,比如可以直接转成html,制作电子书等.今天开始学习一下这个神奇的编辑器.从今天起把 ...

  8. 吴恩达深度学习:2.3梯度下降Gradient Descent

    1.用梯度下降算法来训练或者学习训练集上的参数w和b,如下所示,第一行是logistic回归算法,第二行是成本函数J,它被定义为1/m的损失函数之和,损失函数可以衡量你的算法的效果,每一个训练样例都输 ...

  9. 【学习总结】快速上手Linux玩转典型应用-第5章-远程连接SSH专题

    课程目录链接 快速上手Linux玩转典型应用-目录 目录 1. 认识SSH 2. 服务器安装SSH服务 3. 客户端安装SSH工具 4. 客户端链接SSH服务 5. SSH config 6. SSH ...

  10. logname - 显示用户登录名

    总览 (SYNOPSIS) logname [OPTION]... 描述 (DESCRIPTION) 显示 当前用户 的 名字. --help 显示 帮助信息, 然后 结束. --version 显示 ...