码迷,mamicode.com
首页 > 其他好文 > 详细

hdu 4288 线段树 + 离散化

时间:2015-07-29 22:35:59      阅读:206      评论:0      收藏:0      [点我收藏+]

标签:

题意:求一个动态的非递减序列中,下标 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\n", 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\n", 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\n", 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\n", Query(1, tot, 1, tot, 1, 0));
146                 break;
147             }
148         }
149     }
150 }

 

hdu 4288 线段树 + 离散化

标签:

原文地址:http://www.cnblogs.com/AC-Phoenix/p/4687308.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!