• 习题: codevs 2492 上帝造题的七分钟2 解题报告


    这道题是受到大犇MagHSK的启发我才得以想出来的,蒟蒻觉得自己的代码跟MagHSK大犇的代码完全比不上,所以这里蒟蒻就套用了MagHSK大犇的代码(大家可以关注下我的博客,友情链接就是大犇MagHSK的博客,大神是山东省队队员,他的博客中的题的质量都比我高几个档次);

    这是大神MagHSK的解释:因为10^9顶多开5~6次方就成了1了(当然这里的等于是向下取整的)因此对于修改操作,如果某一段不是1或不是0,就暴力修改,如果是1/0就不管他。修改完之后update一下就好了。

    题目上说我们给出的是一个可修改(修改的规则就是对要修改的区间内每个数开平方)、可查询(就是求一段区间上所有数字的和)的一个数列。

    显然我们直接暴力的效率是很低的,那么我们就采取了线段树——一种神奇的数据结构。

    线段树作为可修改可查询的数据结构,基本操作就是点更新、区间更新和区间查询(包括最小值、最大值和区间和)这里因为是解题报告,所以就不跟大家讲基本思路了,直接进入正题,基本思路和代码板子请自己去看。

    这里因为是对区间内的数开平方,所以区间更新就有点不大好用了(主要是没法直接标记区间然后开平方,这样会计算错误),然后数据范围也不算大,所以我们就考虑搜索线段树上的每一个在需要update(更新)的区间的所有点进行开方点更新,然后再push_up(往上面推,求出每个线段树上区间的和)上去。这样就可以完成更新任务了。(push_up和change(update)函数代码跟板子上不大一样,all数组就是标记这个区间内的数还值不值得进行开平方操作,显然如果这个区间内的和为1或者0的时候就不用开平方了,change的时候就可以省略了)。

    区间查询的操作就是套板子,这个没什么需要思考的。

    还是那句老话,要先考虑自己写,然后实在不会了再看题解,总是copy别人的代码自己的水平肯定上升得很慢。

    废话不再说,上代码。

     1 #include <cstdio>
     2 #include <algorithm>
     3 #include <cmath>
     4 using namespace std;
     5 typedef long long LL;
     6 const int INF = 1009999999;
     7 int n;
     8 LL sum[500005], A[500005];
     9 bool all[500005];
    10 void pu(int now) {
    11     sum[now] = sum[now << 1] + sum[now << 1 | 1];
    12     all[now] = all[now << 1] && all[now << 1 | 1];
    13 }
    14 void build(int now, int l, int r) {
    15     if (l == r) {
    16         sum[now] = A[l];
    17         if (sum[now] == 1 || sum[now] == 0)
    18             all[now] = true;
    19         return;
    20     }
    21     int mid = (l + r) >> 1;
    22     build(now << 1, l, mid);
    23     build(now << 1 | 1, mid + 1, r);
    24     pu(now);
    25 }
    26 LL query(int now, int l, int r, int ll, int rr) {
    27     if (ll <= l && r <= rr) {
    28         return sum[now];
    29     }
    30     int mid = (l + r) >> 1;
    31     LL ret = 0;
    32     if (ll <= mid) ret += query(now << 1, l, mid, ll, rr);
    33     if (rr > mid) ret += query(now << 1 | 1, mid + 1, r, ll, rr);
    34     return ret;
    35 }
    36 void change(int now, int l, int r, int ll, int rr) {
    37     if (all[now]) {
    38         return;
    39     }
    40     if (l == r) {
    41         sum[now] = sqrt(sum[now]);
    42         if (sum[now] == 1 || sum[now] == 0)
    43             all[now] = true;
    44         return;
    45     }
    46     int mid = (l + r) >> 1;
    47     if (ll <= mid) change(now << 1, l, mid, ll, rr);
    48     if (rr > mid) change(now << 1 | 1, mid + 1, r, ll, rr);
    49     pu(now);
    50 }
    51 int main() {
    52     scanf("%d", &n);
    53     for (int i = 1; i <= n; ++i)
    54         scanf("%lld", A+i);
    55     build(1, 1, n);
    56     int m, x, y, z;
    57     scanf("%d", &m);
    58     while (m--) {
    59         scanf("%d%d%d", &x, &y, &z);
    60         if (y > z) swap(y, z);
    61         if (x==1) {
    62             printf("%lld
    ", query(1, 1, n, y, z));
    63         } else {
    64             change(1, 1, n, y, z);
    65         }
    66     }
    67     return 0;
    68 }

    这次解题报告就完结啦,蒟蒻一般是在每周的星期三晚和星期天晚发解题报告,大家就不要在其他时间翻我的博客啦。

  • 相关阅读:
    【转】ubuntu 12.04 LTS 网络配置要点
    Sqlite3在FS_S5PC100开发板上的移植
    java中常用的字符串的截取方法
    一种很好的程序调试方法!
    win7修复MBR
    .tar.xz文件的解压
    linux环境下LED驱动编程一例
    Eclipse设置:背景与字体大小和xml文件中字体大小调整
    ARM LDR与MOV的区别
    windows下从任意目录快速进入CMD
  • 原文地址:https://www.cnblogs.com/gangding/p/5550921.html
Copyright © 2020-2023  润新知