zoukankan      html  css  js  c++  java
  • 【POJ3468】【zkw线段树】A Simple Problem with Integers

    Description

    You have N integers, A1, A2, ... , AN. You need to deal with two kinds of operations. One type of operation is to add some given number to each number in a given interval. The other is to ask for the sum of numbers in a given interval.

    Input

    The first line contains two numbers N and Q. 1 ≤ N,Q ≤ 100000.
    The second line contains N numbers, the initial values of A1, A2, ... , AN. -1000000000 ≤ Ai ≤ 1000000000.
    Each of the next Q lines represents an operation.
    "C a b c" means adding c to each of Aa, Aa+1, ... , Ab. -10000 ≤ c ≤ 10000.
    "Q a b" means querying the sum of Aa, Aa+1, ... , Ab.

    Output

    You need to answer all Q commands in order. One answer in a line.

    Sample Input

    10 5
    1 2 3 4 5 6 7 8 9 10
    Q 4 4
    Q 1 10
    Q 2 4
    C 3 6 3
    Q 2 4
    

    Sample Output

    4
    55
    9
    15

    Hint

    The sums may exceed the range of 32-bit integers.

    Source

    【分析】
    很不错的数据结构,真的很不错....
    跟树状数组有点像..
    相比与普通线段树,zkw线段树具有标记永久化,简单好写的特点。
    但zkw线段树占用的空间会相对大些,毕竟是2的阶乘...,然后应该不能可持久化吧(别跟我说用可持久化线段树维护可持久化数组....)
    这样就不能动态分配内存了。。不过总体来说还是有一定的实用价值...
      1 /*
      2 宋代陆游
      3 《临安春雨初霁》
      4 
      5 世味年来薄似纱,谁令骑马客京华。
      6 小楼一夜听春雨,深巷明朝卖杏花。
      7 矮纸斜行闲作草,晴窗细乳戏分茶。
      8 素衣莫起风尘叹,犹及清明可到家。 
      9 */
     10 #include <iostream>
     11 #include <cstdio>
     12 #include <algorithm>
     13 #include <cstring>
     14 #include <vector>
     15 #include <utility>
     16 #include <iomanip>
     17 #include <string>
     18 #include <cmath>
     19 #include <queue>
     20 #include <assert.h>
     21 #include <map>
     22 #include <ctime>
     23 #include <cstdlib>
     24 #include <stack>
     25 #define LOCAL
     26 const int INF = 0x7fffffff;
     27 const int MAXN = 100000 + 10;
     28 const int maxnode = 300000;
     29 using namespace std;
     30 struct Node{
     31     int l, r;
     32     long long sum, d;    
     33 }tree[maxnode];
     34 int data[MAXN], M;//M为总结点个数        
     35 
     36 //初始化线段树 
     37 void build(int l, int r){
     38     for (int i = 2 * M - 1; i > 0; i--){
     39         if (i >= M){
     40             tree[i].sum = data[i - M];
     41             tree[i].l = tree[i].r = (i - M);//叶子节点 
     42         }
     43         else {
     44             tree[i].sum = tree[i<<1].sum + tree[(i<<1)+1].sum;
     45             tree[i].l = tree[i<<1].l;
     46             tree[i].r = tree[(i<<1)+1].r;
     47         }
     48     }
     49 }
     50 long long query(int l, int r){
     51     long long sum = 0;//sum记录和 
     52     int numl = 0, numr = 0;
     53     l += M - 1;
     54         r += M + 1;
     55     while ((l ^ r) != 1){
     56           if (~l&1){//l取反,表示l是左节点 
     57               sum += tree[l ^ 1].sum;
     58               numl += (tree[l ^ 1].r - tree[l ^ 1].l + 1);
     59            }
     60            if (r & 1){
     61               sum += tree[r ^ 1].sum;
     62               numr += (tree[r ^ 1].r - tree[r ^ 1].l + 1);
     63            }
     64            l>>=1;
     65            r>>=1;
     66            //numl,numr使用来记录标记的 
     67            sum += numl * tree[l].d;
     68            sum += numr * tree[r].d;
     69     }
     70     for (l >>= 1; l > 0; l >>= 1)  sum += (numl + numr) * tree[l].d; 
     71     return sum;
     72 }
     73 
     74 void add(int l, int r, int val){
     75      int numl = 0, numr = 0;
     76      l += M - 1;
     77      r += M + 1;
     78      while ((l ^ r) != 1){
     79            if (~l&1){//l取反 
     80               tree[l ^ 1].d += val;
     81               tree[l ^ 1].sum += (tree[l ^ 1].r - tree[l ^ 1].l + 1) * val;
     82               numl += (tree[l ^ 1].r - tree[l ^ 1].l + 1);
     83            }
     84            if (r & 1){
     85               //更新另一边 
     86               tree[r ^ 1].d += val;
     87               tree[r ^ 1].sum += (tree[r ^ 1].r - tree[r ^ 1].l + 1) * val;
     88               numr += (tree[r ^ 1].r - tree[r ^ 1].l + 1);
     89            }
     90            l>>=1;
     91            r>>=1;
     92            tree[l].sum += numl * val;
     93            tree[r].sum += numr * val;
     94      }
     95      //不要忘了往上更新 
     96      for (l >>= 1; l > 0; l >>= 1)  tree[l].sum += (numl+numr) * val; 
     97 }
     98 int    n, m;
     99 
    100 void init(){
    101      scanf("%d%d", &n, &m);
    102      for (int i = 1; i <= n; i++) scanf("%d", &data[i]);
    103      M = 1;while (M < (n + 2)) M <<= 1;//找到最大的段 
    104      build(0, M - 1);
    105 }
    106 void work(){
    107      while (m--){
    108             char str[2];
    109             scanf("%s", str);
    110             if (str[0] == 'Q'){
    111             int l, r;
    112             scanf("%d%d", &l, &r);
    113             printf("%lld
    ", query(l, r));
    114         }
    115         else{
    116             int val, l, r;
    117             scanf("%d%d%d", &l, &r, &val);
    118             if (val != 0) add(l, r, val);
    119         }
    120      }
    121 }
    122 
    123 int main(){
    124     
    125     init();
    126     work();
    127     return 0;
    128 }
    View Code
  • 相关阅读:
    poj----1330Nearest Common Ancestors(简单LCA)
    Tarjan--LCA算法的个人理解即模板
    hdu----(4545)魔法串(LCS)
    hdu---(1325)Is It A Tree?(并查集)
    hdu----(1599)最大子矩阵(几何/dp)
    hdu---(1054)Strategic Game(最小覆盖边)
    整理的一些模版LCS(连续和非连续)
    hdu---(4310)Hero(贪心算法)
    hdu----(4308)Saving Princess claire_(搜索)
    hdu------(4302)Holedox Eating(树状数组+二分)
  • 原文地址:https://www.cnblogs.com/hoskey/p/4340214.html
Copyright © 2011-2022 走看看