zoukankan      html  css  js  c++  java
  • HDU4027 Can you answer these queries? —— 线段树 区间修改

    题目链接:https://vjudge.net/problem/HDU-4027

    A lot of battleships of evil are arranged in a line before the battle. Our commander decides to use our secret weapon to eliminate the battleships. Each of the battleships can be marked a value of endurance. For every attack of our secret weapon, it could decrease the endurance of a consecutive part of battleships by make their endurance to the square root of it original value of endurance. During the series of attack of our secret weapon, the commander wants to evaluate the effect of the weapon, so he asks you for help. 
    You are asked to answer the queries that the sum of the endurance of a consecutive part of the battleship line. 

    Notice that the square root operation should be rounded down to integer.

    InputThe input contains several test cases, terminated by EOF. 
      For each test case, the first line contains a single integer N, denoting there are N battleships of evil in a line. (1 <= N <= 100000) 
      The second line contains N integers Ei, indicating the endurance value of each battleship from the beginning of the line to the end. You can assume that the sum of all endurance value is less than 2 63
      The next line contains an integer M, denoting the number of actions and queries. (1 <= M <= 100000) 
      For the following M lines, each line contains three integers T, X and Y. The T=0 denoting the action of the secret weapon, which will decrease the endurance value of the battleships between the X-th and Y-th battleship, inclusive. The T=1 denoting the query of the commander which ask for the sum of the endurance value of the battleship between X-th and Y-th, inclusive. 
    OutputFor each test case, print the case number at the first line. Then print one line for each query. And remember follow a blank line after each test case.Sample Input

    10
    1 2 3 4 5 6 7 8 9 10
    5
    0 1 10
    1 1 10
    1 1 5
    0 5 8
    1 4 8

    Sample Output

    Case #1:
    19
    7
    6

    题解:

    1.因为对区间的操作是:对每个数进行开根,所以不能像以前加减操作那样,也直接对区间的和进行操作(因为:a+b=sum 不能推出 根号(a)+根号(b) = 根号(a+b))。

    2.根据上一点,所以在线段树中,我们只能对一段区间一直更新到每一个元素,然后再push_up求和。但是,如果每个操作都如此,那复杂度得多大?直接用数组维护比线段树更快,那要线段树何用?

    3.再回看题目,数据最大为2^64,然后操作是对其开根,我们可以知道对1开根还是1,即当一个值是1时,我们不需要对其进行操作了。推广到一个区间:如果这个区间的所有元素都为1,那么我们也不需要再对这个区间进行操作。那么我们对2^64逐次开根:2^32 2^16 2^8 2^8 2^4 2^2 2^1 1,可以发现,一个数最多只需开7次根就会变成1,操作量很小了。所以:利用线段树进行维护,当一段区间的所有元素都为1,那么我们直接返回;否则更新至叶子结点(深入到每个元素)。

    代码如下:

     1 #include <iostream>
     2 #include <cstdio>
     3 #include <cstring>
     4 #include <cmath>
     5 #include <algorithm>
     6 #include <vector>
     7 #include <queue>
     8 #include <stack>
     9 #include <map>
    10 #include <string>
    11 #include <set>
    12 using namespace std;
    13 typedef long long LL;
    14 const double EPS = 1e-8;
    15 const int INF = 2e9;
    16 const LL LNF = 2e18;
    17 const int MAXN = 1e5+10;
    18 
    19 LL sum[MAXN<<2];
    20 
    21 void push_up(int u)
    22 {
    23     sum[u] = sum[u*2] + sum[u*2+1];
    24 }
    25 
    26 void build(int u, int l, int r)
    27 {
    28     if(l==r)
    29     {
    30         scanf("%lld", &sum[u]);
    31         return;
    32     }
    33 
    34     int mid = (l+r)>>1;
    35     build(u*2, l, mid);
    36     build(u*2+1, mid+1, r);
    37     push_up(u);
    38 }
    39 
    40 void attack(int u, int l, int r, int x, int y)
    41 {
    42     if(l==r)
    43     {
    44         sum[u] = (LL)sqrt(sum[u]);
    45         return;
    46     }
    47     //如果这段区域的每个值都为1,那么就无需再执行操作了
    48     if(x<=l && r<=y && sum[u]==1LL*(r-l+1)) return;
    49 
    50     int mid = (l+r)>>1;
    51     if(x<=mid) attack(u*2, l, mid, x, y);
    52     if(y>=mid+1) attack(u*2+1, mid+1, r, x, y);
    53     push_up(u);
    54 }
    55 
    56 LL query(int u, int l, int r, int x, int y)
    57 {
    58     if(x<=l && r<=y)
    59         return sum[u];
    60 
    61     LL ret = 0;
    62     int mid = (l+r)>>1;
    63     if(x<=mid) ret += query(u*2, l, mid, x, y);
    64     if(y>=mid+1) ret += query(u*2+1, mid+1, r, x, y);
    65     return ret;
    66 }
    67 
    68 int main()
    69 {
    70     int n, m, kase = 0;
    71     while(scanf("%d", &n)!=EOF)
    72     {
    73         build(1, 1, n);
    74         scanf("%d", &m);
    75         printf("Case #%d:
    ", ++kase);
    76         for(int i = 1; i<=m; i++)
    77         {
    78             LL op, x, y;
    79             scanf("%lld%lld%lld", &op, &x, &y);
    80             int xx = min(x, y), yy = max(x, y);
    81             if(op==0) attack(1, 1, n, xx, yy );
    82             else printf("%lld
    ", query(1, 1, n, xx, yy) );
    83         }
    84         printf("
    ");
    85     }
    86 }
    View Code
  • 相关阅读:
    nginx.conf文件
    本地apache 可以正常访问,lnmp服务器访问404错误
    PHP网站从Apache转移到Nginx后产生404错误的原因和解决办法
    CGI,FAST-CGI,PHP-FPM的区别
    Lnmp修改php.ini配置
    APACHE服务器出现No input file specified.的完美解决方案
    EXCEL常用函数详解
    chrome extensions
    C++使用OLE高速读写EXCEL的源码
    C++读写EXCEL文件OLE,java读写excel文件POI 对比
  • 原文地址:https://www.cnblogs.com/DOLFAMINGO/p/7726053.html
Copyright © 2011-2022 走看看