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

hdu 4288 线段树

时间:2015-03-22 00:27:23      阅读:157      评论:0      收藏:0      [点我收藏+]

标签:

没看懂先mark

题意:
维护一个有序数列{An},有三种操作:
1、添加一个元素。
2、删除一个元素。
3、求数列中下标%5 = 3的值的和。
解题思路:
看的各种题解,今天终于弄懂了。
由于线段树中不支持添加、删除操作,所以题解写的是用离线做法。
我们来看它是如何解决添加、删除的问题的。
首先将所有出现过的数记录下来,然后排序去重,最后根据去重结果建树,然后每个操作数都会对应线段树中的一个点。
遇到添加、删除操作的时候,只要把那个节点的值改变,然后将它对下标的影响处理好就可以。
那么如何处理这些操作对下标的影响呢?
现在我们考虑一个父区间,假设它的左右子区间已经更新完毕。
显然,左区间中下标%5的情况与父区间中%5的情况完全相同;
可是,右区间中却不一定相同,因为右区间中的下标是以 mid 当作 1 开始的。
那么,只要我们知道左区间中有效元素的个数 cnt,我们就能知道右区间中的下标 i 在父区间中对应的下标为 i+cnt。
所以,虽然我们最终要的只是总区间中下标%5 = 3的和。但是在更新时我们需要知道右区间%5的所有情况。
于是我们要在线段树的每个节点开一个 sum[5] 和一个 cnt,分别记录这个节点中下标%5的5种情况的和与有效元素的个数。
而查询时,直接访问总区间的 sum[3] 即可。
如此,题目便可解了。复杂度O(M logN logN)。

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <iostream>
 4 #include <map>
 5 #include <set>
 6 #include <vector>
 7 #include <string>
 8 #include <queue>
 9 #include <deque>
10 #include <bitset>
11 #include <list>
12 #include <cstdlib>
13 #include <climits>
14 #include <cmath>
15 #include <ctime>
16 #include <algorithm>
17 #include <stack>
18 #include <sstream>
19 #include <numeric>
20 #include <fstream>
21 #include <functional>
22 
23 using namespace std;
24 
25 #define MP make_pair
26 #define PB push_back
27 #define lson rt << 1,l,mid
28 #define rson rt << 1 | 1,mid + 1,r
29 typedef long long LL;
30 typedef unsigned long long ULL;
31 typedef vector<int> VI;
32 typedef pair<int,int> pii;
33 const int INF = INT_MAX / 3;
34 const double eps = 1e-8;
35 const LL LINF = 1e17;
36 const double DINF = 1e60;
37 const int maxn = 1e5 + 10;
38 VI num;
39 char buf[1024],cmd[maxn];
40 int val[maxn],knum,cnt[maxn << 2],n;
41 LL sum[maxn << 2][5];
42 
43 int getID(int v) {
44     return lower_bound(num.begin(),num.end(),v) - num.begin() + 1;
45 }
46 
47 void pushup(int rt,int l,int r) {
48     int lc = rt << 1, rc = rt << 1 | 1;
49     cnt[rt] = cnt[lc] + cnt[rc];
50     for(int i = 0;i < 5;i++) sum[rt][i] = sum[lc][i];
51     for(int i = 0;i < 5;i++) sum[rt][(i + cnt[lc]) % 5] += sum[rc][i];
52 }
53 
54 void update(int rt,int l,int r,int pos,int tar) {
55     //printf("%d %d %d %d %d\n",pos,tar,l,r,rt);
56     int mid = (l + r) >> 1;
57     if(l == r) {
58         sum[rt][1] = num[pos - 1] * tar;
59         //printf("%d\n",sum[rt][1]);
60         cnt[rt] = tar;
61     }
62     else {
63         if(pos <= mid) update(lson,pos,tar);
64         else update(rson,pos,tar);
65         pushup(rt,l,r);
66     }
67 }
68 
69 int main() {
70     #ifndef ONLINE_JUDGE
71     freopen("1.in","r",stdin);
72     #endif
73     while(~scanf("%d",&n)) {
74         num.clear();
75         for(int i = 1;i <= n;i++) {
76             scanf("%s",buf); cmd[i] = buf[0];
77             if(cmd[i] != s) {
78                 scanf("%d",&val[i]);
79                 num.PB(val[i]);
80             }
81         }
82         memset(sum,0,sizeof(sum));
83         memset(cnt,0,sizeof(cnt));
84         sort(num.begin(),num.end());
85         num.erase(unique(num.begin(),num.end()),num.end());
86         knum = num.size();
87         for(int i = 1;i <= n;i++) {
88             if(cmd[i] == a) update(1,1,knum,getID(val[i]),1);
89             else if(cmd[i] == d) update(1,1,knum,getID(val[i]),0);
90             else printf("%I64d\n",sum[1][3]);
91         }
92     }
93     return 0;
94 }

 

hdu 4288 线段树

标签:

原文地址:http://www.cnblogs.com/cnblogs321114287/p/4356512.html

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