• POJ 3468 A Simple Problem with Integers (splay tree入门)


    A Simple Problem with Integers
    Time Limit: 5000MS   Memory Limit: 131072K
    Total Submissions: 47944   Accepted: 14122
    Case Time Limit: 2000MS

    Description

    You have N integers, A1A2, ... , 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 A1A2, ... , AN. -1000000000 ≤ Ai ≤ 1000000000.
    Each of the next Q lines represents an operation.
    "C a b c" means adding c to each of AaAa+1, ... , Ab. -10000 ≤ c ≤ 10000.
    "Q a b" means querying the sum of AaAa+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

     
     
     
     
     
     
     
     
      1 /* ***********************************************
      2 Author        :kuangbin
      3 Created Time  :2013/8/24 22:13:15
      4 File Name     :F:2013ACM练习专题学习splay_tree_2POJ3468.cpp
      5 ************************************************ */
      6 
      7 #include <stdio.h>
      8 #include <string.h>
      9 #include <iostream>
     10 #include <algorithm>
     11 #include <vector>
     12 #include <queue>
     13 #include <set>
     14 #include <map>
     15 #include <string>
     16 #include <math.h>
     17 #include <stdlib.h>
     18 #include <time.h>
     19 using namespace std;
     20 //普通的线段树操作,区间增加一个值,查询区间的和
     21 #define Key_value ch[ch[root][1]][0]
     22 const int MAXN = 100010;
     23 int pre[MAXN],ch[MAXN][2],root,tot1;
     24 int size[MAXN];//子树的结点数
     25 int add[MAXN];//增量的延迟标记
     26 int key[MAXN];
     27 long long sum[MAXN];//子树的和
     28 int s[MAXN],tot2;//内存池和容量
     29 int a[MAXN];//初始的数组,建树的时候用,下标从1开始
     30 
     31 //debug部分**********************************
     32 void Treavel(int x)
     33 {
     34     if(x)
     35     {
     36         Treavel(ch[x][0]);
     37         printf("结点:%2d: 左儿子 %2d 右儿子 %2d 父结点 %2d size = %2d add = %2d sum = %I64d
    ",x,ch[x][0],ch[x][1],pre[x],size[x],add[x],sum[x]);
     38         Treavel(ch[x][1]);
     39     }
     40 }
     41 void debug()
     42 {
     43     printf("root:%d
    ",root);
     44     Treavel(root);
     45 }
     46 //以上是debug部分**************************************
     47 
     48 void NewNode(int &r,int father,int k)
     49 {
     50     if(tot2)r = tot2--;//取的时候是tot2--,存的时候就是++tot2
     51     else r = ++tot1;
     52     pre[r] = father;
     53     size[r] = 1;
     54     add[r] = 0;
     55     key[r] = k;
     56     sum[r] = k;
     57     ch[r][0] = ch[r][1] = 0;
     58 }
     59 //给r为根的子树增加值,把当前结点更新掉,加延迟标记
     60 void Update_Add(int r,int ADD)
     61 {
     62     if(r == 0)return;
     63     add[r] += ADD;
     64     key[r] += ADD;
     65     sum[r] += (long long)ADD*size[r];
     66 }
     67 void push_up(int r)
     68 {
     69     size[r] = size[ch[r][0]] + size[ch[r][1]] + 1;
     70     sum[r] = sum[ch[r][0]] + sum[ch[r][1]] + key[r];
     71 }
     72 void push_down(int r)
     73 {
     74     if(add[r])
     75     {
     76         Update_Add(ch[r][0],add[r]);
     77         Update_Add(ch[r][1],add[r]);
     78         add[r] = 0;
     79     }
     80 }
     81 //建树
     82 void Build(int &x,int l,int r,int father)
     83 {
     84     if(l > r)return;
     85     int mid = (l+r)/2;
     86     NewNode(x,father,a[mid]);
     87     Build(ch[x][0],l,mid-1,x);
     88     Build(ch[x][1],mid+1,r,x);
     89     push_up(x);
     90 }
     91 int n,q;
     92 //初始化
     93 void Init()
     94 {
     95     root = tot1 = tot2 = 0;
     96     ch[root][0] = ch[root][1] = pre[root] = size[root] = add[root] = sum[root] = key[root] = 0;
     97     //加两个虚结点
     98     NewNode(root,0,-1);
     99     NewNode(ch[root][1],root,-1);
    100     for(int i = 1;i <= n;i++)
    101         scanf("%d",&a[i]);
    102     Build(Key_value,1,n,ch[root][1]);
    103     push_up(ch[root][1]);
    104     push_up(root);
    105 }
    106 //旋转,0为左旋,1为右旋
    107 void Rotate(int x,int kind)
    108 {
    109     int y = pre[x];
    110     push_down(y);
    111     push_down(x);//先把y的标记下传,在把x的标记下传
    112     ch[y][!kind] = ch[x][kind];
    113     pre[ch[x][kind]] = y;
    114     if(pre[y])
    115         ch[pre[y]][ch[pre[y]][1]==y] = x;
    116     pre[x] = pre[y];
    117     ch[x][kind] = y;
    118     pre[y] = x;
    119     push_up(y);
    120 }
    121 //Splay调整,将r结点调整到goal下面
    122 void Splay(int r,int goal)
    123 {
    124     push_down(r);
    125     while(pre[r] != goal)
    126     {
    127         if(pre[pre[r]] == goal)
    128             Rotate(r,ch[pre[r]][0]==r);
    129         else
    130         {
    131             int y = pre[r];
    132             int kind = ch[pre[y]][0]==y;
    133             if(ch[y][kind] == r)
    134             {
    135                 Rotate(r,!kind);
    136                 Rotate(r,kind);
    137             }
    138             else
    139             {
    140                 Rotate(y,kind);
    141                 Rotate(r,kind);
    142             }
    143         }
    144     }
    145     push_up(r);
    146     if(goal == 0) root = r;
    147 }
    148 //得到第k个结点
    149 int Get_kth(int r,int k)
    150 {
    151     push_down(r);
    152     int t = size[ch[r][0]] + 1;
    153     if(t == k)return r;
    154     if(t > k)return Get_kth(ch[r][0],k);
    155     else return Get_kth(ch[r][1],k-t);
    156 }
    157 
    158 //区间增加一个值
    159 //因为加了个空结点,所以将第l个点旋转到根结点,第r+2个点旋转到根结点的右孩子
    160 //那么Key_value就是需要修改的区间[l,r]
    161 void ADD(int l,int r,int D)
    162 {
    163     Splay(Get_kth(root,l),0);
    164     Splay(Get_kth(root,r+2),root);
    165     Update_Add(Key_value,D);
    166     push_up(ch[root][1]);
    167     push_up(root);
    168 }
    169 //查询区间的和
    170 long long Query_sum(int l,int r)
    171 {
    172     Splay(Get_kth(root,l),0);
    173     Splay(Get_kth(root,r+2),root);
    174     return sum[Key_value];
    175 }
    176 
    177 int main()
    178 {
    179     //freopen("in.txt","r",stdin);
    180     //freopen("out.txt","w",stdout);
    181     while(scanf("%d%d",&n,&q) == 2)
    182     {
    183         Init();
    184         //debug();
    185         int x,y,z;
    186         char op[20];
    187         while(q--)
    188         {
    189             scanf("%s",op);
    190             if(op[0] == 'Q')
    191             {
    192                 scanf("%d%d",&x,&y);
    193                 printf("%I64d
    ",Query_sum(x,y));
    194             }
    195             else
    196             {
    197                 scanf("%d%d%d",&x,&y,&z);
    198                 ADD(x,y,z);
    199             }
    200         }
    201     }
    202     return 0;
    203 }
     
     
  • 相关阅读:
    个人信息
    两个整数的最小公倍数和最大公约数
    java杨辉三角实现
    只会用这简单的递归求阶乘
    图形界面设计
    圆的面积,周长,圆柱体的体积(类的封装与抽象)
    杨辉三角
    1~10的阶乘java语言编程
    个人信息与计算器
    个人信息显示界面
  • 原文地址:https://www.cnblogs.com/kuangbin/p/3280159.html
Copyright © 2020-2023  润新知