zoukankan      html  css  js  c++  java
  • HDU 4027 Can you answer these queries【线段树】

    <题目链接>

    题目大意:

    给定一段序列,现在对指定区间进行两种操作:一是对指定区间进行修改,对其中的每个数字都开根号(开根号后的数字仍然取整);二是对指定区间进行查询,查询这段区间所有数字的和。

    解题分析:

    本题虽然是区间修改,但是不需要用 lazy标记,因为要对指定区间的每个数进行开根号的处理,也就是说,每次 update ,都要延伸到该区间涉及到的叶子节点,进行开根,而不是在叶子节点上端的某个节点就将开根的指令存储下来。那么是不是说我们每次只能对 update 的每个区间所涉及到的每个节点进行暴力的单点修改呢?很显然不是的,因为每个节点的值不超过2^63,所以每个值的有效开方次数并不多。所以我们对线段树的每个节点引入一个标记cnt,用它来记录该节点对应的区域是否全部不需要开方,如果不需要开方,那么就直接return ,终止无效更新,从而提高效率。

     1 #include <cstdio>
     2 #include <cstring>
     3 #include <cmath>
     4 #include <algorithm>
     5 using namespace std;
     6 
     7 #define Lson rt<<1,l,mid
     8 #define Rson rt<<1|1,mid+1,r
     9 typedef long long ll;
    10 const int M = 1e5+5;
    11 int n;
    12 ll tr[M<<2],arr[M];
    13 bool fp[M<<2];
    14 void Pushup(int rt){
    15     if(fp[rt<<1]&&fp[rt<<1|1])fp[rt]=true;    //如果两个子区间全部不用开根号的话,那么该区间也标记为不用继续开根
    16     else fp[rt]=false;
    17     tr[rt]=tr[rt<<1]+tr[rt<<1|1];
    18 }
    19 void build(int rt,int l,int r){
    20     if(l==r){
    21         tr[rt]=arr[l];
    22         return;
    23     }
    24     int mid=(l+r)>>1;
    25     build(Lson);
    26     build(Rson);
    27     Pushup(rt);
    28 }
    29 void update(int rt,int l,int r,int L,int R){
    30     if(fp[rt])return;      //如果遍历到不用继续向下更新的区间,则直接返回
    31     if(l==r){
    32         tr[rt]=sqrt(tr[rt]*1.0);
    33         if(tr[rt]==1)fp[rt]=true;    //如果tr[rt]==1,那么该点就标记为不用继续开根
    34         return;
    35     }
    36     int mid=(l+r)>>1;
    37     if(L<=mid)update(Lson,L,R);
    38     if(R>mid)update(Rson,L,R);
    39     Pushup(rt);
    40 }
    41 ll query(int rt,int l,int r,int L,int R){
    42     if(L<=l&&r<=R){
    43         return tr[rt];
    44     }
    45     int mid=(l+r)>>1;
    46     ll ans=0;
    47     if(L<=mid)ans+=query(Lson,L,R);
    48     if(R>mid)ans+=query(Rson,L,R);
    49     return ans;
    50 }
    51 int main(){
    52     int ncase=0;
    53     while(scanf("%d",&n)!=EOF){
    54         memset(fp,false,sizeof(fp));
    55         for(int i=1;i<=n;i++)scanf("%lld",&arr[i]);
    56         build(1,1,n);
    57         int m;scanf("%d",&m);
    58         printf("Case #%d:
    ",++ncase);
    59         while(m--){
    60             int op,x,y;
    61             scanf("%d%d%d",&op,&x,&y);
    62             if(x>y)swap(x,y);    //注意这里,坑
    63             if(op==0){
    64                 update(1,1,n,x,y);
    65             }
    66             else{
    67                 printf("%lld
    ",query(1,1,n,x,y));
    68             }
    69         }
    70         printf("
    ");
    71     }
    72     return 0;
    73 }

    2018-09-23

  • 相关阅读:
    Qt之等待提示框(QTimer)
    Qt之等待提示框(QPropertyAnimation)
    FormatUtil类型格式转换
    FirstLetterUtil
    文件上传下载
    file相关的操作,(md5,word转html,复制,删除等)
    SessionListener失败,退出
    JackJson的一些方法
    全局常量
    session用户账号认证(一个用户登陆,踢出前一个用户)
  • 原文地址:https://www.cnblogs.com/00isok/p/9693144.html
Copyright © 2011-2022 走看看