zoukankan      html  css  js  c++  java
  • hdu-4027线段树练习


    title: hdu-4027线段树练习
    date: 2018-10-10 18:07:11
    tags:

    • acm
    • 算法
    • 刷题
      categories:
    • ACM-线段树

    概述

    这道线段树的题可以说是我这一段时间复习线段树后第一次认认真真的做的第一道线段树的题了吧,,,,

    然后,,,看似很简单的题翻车了,,,,QAQ

    题意和分析

    题意大概就是给你一些数,,然后对[l , r]这个区间里的所有数进行开平方根运算,,,其中还有一些询问[l , r]的区间和,,,

    看到一排数列的区间和还有更新询问操作的题型铁定是要用线段树来维护这个数列了,,,

    一开始我想着结点保存两个区间和,,一个是现在未更新的区间和,,另一个是每个开方后的区间和,,,然后用lazy来延迟更新,,,然后貌似在更新时这样会少更新,,,最后的答案肯定就不对了,,

    最后,,,坑了两个多小时的我还是去找别人的做法了,,,

    这道题首先一点就是即使数字很大,,,但是 (2^{63} - 1) 也就最多开8次平方根,,,而且开到1时再开平方根还是1,,,,

    所以再开到区间所有数都为1时就不再对这个区间更新,,,也就是当 node[rt].sum == node[rt].r - node[rt].l + 1 时就返回上一层,,,这样就减小了更新时的操作,,,

    最终的代码,,,

    #include <iostream>
    #include <cstdio>
    #include <cstdlib>
    #include <cmath>
    #include <algorithm>
    using namespace std;
    typedef long long ll;
    const int maxn = 1e5 + 10;
    int n, q;
    ll a[maxn];
    struct tree
    {
       int l;
       int r;
       ll sum;
    }node[maxn << 2];
    
    void pushup(int rt)
    {
       node[rt].sum = node[rt << 1].sum + node[rt << 1 | 1].sum;
    }
    
    void build(int rt , int l , int r)
    {
       node[rt].l = l;
       node[rt].r = r;
    
       if (l == r)
       {
           node[rt].sum = a[l];
           return;                 //要记得return,,,最近写这个总是忘记写
       }
    
       int mid = (l + r) >> 1;
    
       build(rt << 1 , l , mid);
       build(rt << 1 | 1 , mid + 1 , r);
       pushup(rt);
       return;
    }
    
    void update(int rt , int L , int R)
    {
       if (node[rt].sum == node[rt].r - node[rt].l + 1)
           return;                 //区间全为1时返回,,,不然会tle
       if (node[rt].l == node[rt].r)
       {
           node[rt].sum = (ll)(sqrt(node[rt].sum));    //直接开方就行了
           return;
       }
    
       int mid = (node[rt].l + node[rt].r) >> 1;
       if (L <= mid)   update(rt << 1 , L , R);
       if (R >  mid)   update(rt << 1 | 1 , L , R);
       pushup(rt);
       return;
    }
    ll query(int rt , int L , int R)
    {
    
       if (L <= node[rt].l && node[rt].r <= R)
       {
           return node[rt].sum;
       }
       
       int mid = (node[rt].l + node[rt].r) >> 1;
       ll ans = 0;
       if (L <= mid)    ans += query(rt << 1 , L , R);
       if (R >  mid)    ans += query(rt << 1 | 1 , L , R);
       return ans;
    }
    
    int main(int argc, char const *argv[])
    {
       int i = 0;
       while(scanf("%d" , &n) != EOF)
       {
           printf("Case #%d:
    " , ++i);
           for (int i = 1; i <= n; ++i)
               scanf("%lld" , &a[i]);
    
           build(1 , 1 , n);
    
           scanf("%d" , &q);
    
           while(q--)
           {
               int t , l , r;
               scanf("%d%d%d" , &t , &l , &r);
               if (l > r)
                   swap(l , r);        //l , r不一定保证 l <= r 所以要判断
    
               if (t)
                   printf("%lld
    " , query(1 , l , r));
               else
                   update(1 , l , r);
           }
           printf("
    ");               //每组测试样例之间加空行
       }
       return 0;
    }
    

    总结

    • 没看出来一个数最多开方8次啊,,,
    • 还是不能仔细的读题,,,比如那个输入的l , r比如那个每一组测试样例之间加空行
    • 想的太多了,,,而且最主要的是还是想着套模板解题,,,而不是就题而选择怎么写
    • ,,,,

    还是做的题太少了,,还是有点像暑假时见到线段树就套板子,,套板子,,已经好几次套板子是没用的情况了,,,而且除了入门的线段树的题,,,都不是之套板子就能出结果的,,,都要在某些地方加一些判断,,,或者对数据的处理,,,线段树只是众多工具之一啊,,不是万能的呐,,,,

    (end)

    动手总比只想所得到的多一些,,即使结果不尽人意呐~

    剑之所指,心之所向,身之所往!!!
  • 相关阅读:
    女孩提出分手的N种理由
    Attribute应用,简化ANF自定义控件初始化过程
    关于Web的动态页面与静态页面分开的想法.
    .Net面试题
    算法题,不用递归,构造树型
    花两个小时,做了个分页控件
    事件应用,为系统提供扩展功能
    绘制半透明的图片
    Tile Studio简介(转载)
    Thinking in Java 摘录笔记
  • 原文地址:https://www.cnblogs.com/31415926535x/p/9768309.html
Copyright © 2011-2022 走看看