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\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 }