zoukankan      html  css  js  c++  java
  • hdu 4288 线段树 + 离散化

    题意:求一个动态的非递减序列中,下标 mod 5 == 3的元素和,可以向序列中添加和删除某些元素,且序列的单调性不变。保证在任意时间 序列中不会存在两个相同元素。保证输入合法

    思路:保证在任意时间 序列中不会存在两个相同元素,也就说明如果将所有的值都插入序列中,每个值对应的位置是唯一的。所以将操作的值先保存下来,离散化处理出每个值对应的位置。离散化后,我们得到一个新的数列 uni_num[] 。通过题意的描述,我们可以发现一个性质,每当我们在 i 位置插入或者删除一个 uni_num[k] 时,题意描述的动态序列的区间 [l, i - 1] 中的下标 mod 5 == 3的元素和没有发生变化,区间 [i + 1, r] 上的所求元素和变成了之前的下标 mod 5 == 2 或者 下标 mod 5 == 4 的和。于是想到,在两个区间上分别去维护 5 种sum,再将两个区间的sum合并成总区间的sum,这就有点像线段树的做法了,使用线段树时要保证区间长度固定,于是我们用线段树去维护 uni_num[] 数组。为了使得在对做区间进行元素删减的时候不影响右区间,选取每个区间的最左端作为新的下标为 1 的位置来计算 5 种sum,但是这样我们在合并区间的时候,就需要知道右区间上有多少个元素,所以还需添加一个属性 sz。

    hint:去掉离散化也没问题。如果在某个时刻序列中存在两个元素的值相同也可以用相同的方法做,增加一个数组去维护加入或删除的值在线段树区间上的偏移。

      1 #include "bits/stdc++.h"
      2 using namespace std;
      3 int i;
      4 int M;
      5 char cmd[100010][5];
      6 int num[100010];
      7 
      8 int tot;
      9 int uni_num[100010];
     10 
     11 int Bin(int ans)
     12 {
     13     int l, r, mid;
     14     l = 1, r = tot;
     15     while (l <= r) {
     16         mid = (l + r) >> 1;
     17         if(uni_num[mid] <= ans) {
     18             l = mid + 1;
     19         }
     20         else {
     21             r = mid - 1;
     22         }
     23     }
     24     return r;
     25 }
     26 
     27 #define lson l, m, rt<<1
     28 #define rson m + 1, r, rt<<1|1
     29 const int MAXN = 100010;
     30 struct Node
     31 {
     32     long long sum[5], sz;
     33 }node[MAXN<<2];
     34 
     35 inline void PushUp(int rt)
     36 {
     37     int sz1 = node[rt<<1].sz, i;
     38     for (i = 0; i <= 4; ++i) {
     39         node[rt].sum[i] = node[rt<<1].sum[i] + node[rt<<1|1].sum[((i - (1 + sz1) % 5) + 1 + 5) % 5];
     40     }
     41     node[rt].sz = node[rt<<1].sz + node[rt<<1|1].sz;
     42 }
     43 
     44 void Build(int l, int r, int rt)
     45 {
     46     if (l == r) {
     47         int i;
     48         for (i = 0; i <= 4; ++i) {
     49             node[rt].sum[i] = 0;
     50         }
     51         node[rt].sz = 0;
     52         return ;
     53     }
     54     int m = (l + r)>>1;
     55     Build(lson);
     56     Build(rson);
     57 
     58     PushUp(rt);
     59 }
     60 
     61 //void UpdateAdd(int p, int add, int l, int r, int rt)
     62 //{
     63 //    if (l == r) {
     64 //        node[rt].sum += add;
     65 //        return ;
     66 //    }
     67 //    int m = (l + r) >> 1;
     68 //    if (p <= m) {
     69 //        UpdateAdd(p, add, lson);
     70 //    }
     71 //    else {
     72 //        UpdateAdd(p, add, rson);
     73 //    }
     74 //    PushUp(rt);
     75 //}
     76 
     77 void UpdateModify(int p, int newVal, int l, int r, int rt)
     78 {
     79     if (l == r) {
     80         node[rt].sum[1] = newVal;
     81         if(newVal == 0) {
     82             --node[rt].sz;
     83         }
     84         else {
     85             ++node[rt].sz;
     86         }
     87 //        printf("l == %d r == %d sum[0] == %lld sum[1] == %lld sum[2] == %lld sum[3] == %lld sum[4] == %lld sz == %d
    ", l, r, node[rt].sum[0], node[rt].sum[1], node[rt].sum[2], node[rt].sum[3], node[rt].sum[4], node[rt].sz);
     88         return ;
     89     }
     90     int m = (l + r) >> 1;
     91     if (p <= m) {
     92         UpdateModify(p, newVal, lson);
     93     }
     94     else {
     95         UpdateModify(p, newVal, rson);
     96     }
     97     PushUp(rt);
     98 //    printf("l == %d r == %d sum[0] == %lld sum[1] == %lld sum[2] == %lld sum[3] == %lld sum[4] == %lld sz == %d
    ", l, r, node[rt].sum[0], node[rt].sum[1], node[rt].sum[2], node[rt].sum[3], node[rt].sum[4], node[rt].sz);
     99 }
    100 
    101 long long Query(int L,int R,int l,int r,int rt, int sz1)
    102 {
    103     if (L <= l && r <= R) {
    104         return node[rt].sum[(3 + sz1) % 5];
    105     }
    106     int m = (l + r) >> 1;
    107     int ans = 0;
    108     if (L <= m) {
    109         ans += Query(L, R, lson, sz1);
    110     }
    111     if (R > m) {
    112         ans += Query(L, R, rson, sz1 + node[rt<<1].sz);
    113     }
    114     return ans;
    115 }
    116 
    117 int main()
    118 {
    119     while (scanf("%d", &M) != EOF) {
    120         tot = 0;
    121         for (i = 1; i <= M; ++i) {
    122             scanf("%s", &cmd[i]);
    123             if (cmd[i][0] != 's') {
    124                 scanf("%d", &num[i]);
    125                 ++tot;
    126                 uni_num[tot] = num[i];
    127             }
    128         }
    129         sort(uni_num + 1, uni_num + 1 + tot);
    130         tot = unique(uni_num + 1, uni_num + 1 + tot) - &uni_num[1];
    131         Build(1, tot, 1);
    132         int pos;
    133         for (i = 1; i <= M; ++i) {
    134 //            printf("i == %d
    ", i);
    135             switch(cmd[i][0]) {
    136             case 'a':
    137                 pos = Bin(num[i]);
    138                 UpdateModify(pos, num[i], 1, tot, 1);
    139                 break;
    140             case 'd':
    141                 pos = Bin(num[i]);
    142                 UpdateModify(pos, 0, 1, tot, 1);
    143                 break;
    144             case 's':
    145                 printf("%lld
    ", Query(1, tot, 1, tot, 1, 0));
    146                 break;
    147             }
    148         }
    149     }
    150 }
  • 相关阅读:
    《页面优化》-- 一个大话题,也是一个面试比较老俗的问题
    Single-SPA 前端微服务化 动态路由多系统合并
    浏览器的DNS缓存查看和清除
    es6 的类 class
    数据驱动表格| 根据json数据,自动生成合并式table
    隐式调用 以及使用技巧
    柯里化currying + 隐式调用 = 一个有名的add面试题
    工作笔记
    php升级版本
    git使用
  • 原文地址:https://www.cnblogs.com/AC-Phoenix/p/4687308.html
Copyright © 2011-2022 走看看