Necklace HDU - 3874 (线段树/树状数组 + 离线处理)
Posted 当然是斗笠呀
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Necklace HDU - 3874 (线段树/树状数组 + 离线处理)相关的知识,希望对你有一定的参考价值。
Now Mery thinks the necklace is too long. She plans to take some continuous part of the necklace to build a new one. She wants to know each of the beautiful value of M continuous parts of the necklace. She will give you M intervals [L,R] (1<=L<=R<=N) and you must tell her F(L,R) of them.
InputThe first line is T(T<=10), representing the number of test cases.
For each case, the first line is a number N,1 <=N <=50000, indicating the number of the magic balls. The second line contains N non-negative integer numbers not greater 1000000, representing the beautiful value of the N balls. The third line has a number M, 1 <=M <=200000, meaning the nunber of the queries. Each of the next M lines contains L and R, the query.OutputFor each query, output a line contains an integer number, representing the result of the query.Sample Input
2 6 1 2 3 4 3 5 3 1 2 3 5 2 6 6 1 1 1 2 3 5 3 1 1 2 4 3 5
Sample Output
3 7 14 1 3 6
题意:给n个数字,代表项链每个单位的价值。在给m组查询,代表需要查询的[l,r]中的项链价值的总和;
项链区间价值的计算方法:区间中不同数字的和,即是该区间项链价值的总和。
做法:因为查询的区间已知,采用线段树/树状数组 + 离线查找的方法
将需要查找的区间根据 右端点 从小到大排序。从左往右逐步把数据加入到线段树中,当达到某一查询区间的右端点时,进行一次区间和的计算。
建立一个map数组,若某个数已经在序列中,则在最近出现的位置删除该数,这样就能保证每个数任意时刻只在线段树的中存储一次。
(举个栗子:如样例输入中 map[1] = 1,当第二个1放入线段树的时候,需要将第一个1清除,并更新map[1] = 2,以此保证线段树中该价值仅存在一个,
并且如果区间可以覆盖上一个map[1],那么区间必定可以覆盖现在的map[1]。)
1 #include<stdio.h> 2 #include<string.h> 3 #include<iostream> 4 #include<algorithm> 5 #include<map> 6 #include<string> 7 #include<set> 8 #include<stack> 9 #include<queue> 10 using namespace std; 11 const int maxn = 200010; 12 typedef long long ll; 13 struct node{ 14 int l,r; 15 ll sum; 16 }tree[maxn];//建立线段树 17 ll T,n,m; 18 ll value[maxn],ans[maxn];// ans数组储存答案,value储存每个单位项链的价值 19 map<ll,int> mp;// 储存价值i在数组中最近出现的位置 20 struct node2 21 { 22 int l,r; 23 int index;//题目中要求的访问的顺序 24 }q[maxn]; 25 26 void build(int rt,int left,int right){ 27 tree[rt].l = left; 28 tree[rt].r = right; 29 tree[rt].sum = 0;// 令每个根节点的值都为零,在计算的过程中再更新节点的值 30 if(left == right){ 31 return; 32 }else{ 33 int mid = (left + right)>>1; 34 build(rt<<1,left,mid); 35 build((rt<<1)|1, mid + 1, right); 36 } 37 } 38 void updata(int rt,int pos,ll val){//逐步将数据放入线段树中 39 tree[rt].sum += val; 40 if(tree[rt].l == tree[rt].r && tree[rt].l == pos){ 41 return; 42 } 43 int mid = (tree[rt].l + tree[rt].r)>>1; 44 if(pos <= mid){ 45 updata(rt<<1,pos,val); 46 }else{ 47 updata((rt<<1)|1,pos,val); 48 } 49 } 50 ll query(int rt,int left,int right){ 51 if(tree[rt].l == left && tree[rt].r == right){ 52 return tree[rt].sum; 53 } 54 int mid = (tree[rt].l + tree[rt].r)>>1; 55 if(right <= mid){ 56 return query(rt<<1,left,right); 57 }else if(left > mid){ 58 return query((rt<<1)|1 ,left ,right); 59 }else{ 60 return query(rt<<1,left,mid) + query((rt<<1)|1 ,mid + 1 ,right); 61 } 62 } 63 64 bool cmp(node2 & a, node2 & b){//按照查询区间的右端点从小到大排序 65 return a.r < b.r; 66 } 67 int main(){ 68 scanf("%lld",&T); 69 while(T--){ 70 scanf("%lld",&n); 71 build(1,1,n); 72 mp.clear(); 73 for(int i = 1 ; i <= n ; i++){ 74 scanf("%lld",&value[i]); 75 } 76 scanf("%lld",&m); 77 for(int i = 1 ; i <= m ;i++){ 78 scanf("%d %d",&q[i].l,&q[i].r); 79 q[i].index = i; 80 } 81 sort(q + 1, q + 1 + m , cmp); 82 int id = 1;//代表目前已经计算了几次题目想要查询的区间值 83 for(int i = 1 ; i <= n ; i++){ 84 85 86 updata(1,i,value[i]);//按顺序从左到右将数组中的数据放入线段树中 87 if(mp[value[i]]) updata(1,mp[value[i]],-value[i]); //如果价值value[i],将之前的数据进行删除,并将线段树更新 88 mp[value[i]] = i;// 更新value[i]最新出现的位置 89 90 while(id <= m && q[id].r == i){//当计算次数小于总次数,并且线段树对应下标等于某个查询区间的右端点时,进行一次查询 91 ans[q[id].index] = query(1,q[id].l, q[id].r); 92 id++; 93 } 94 } 95 for(int i = 1 ; i <= m ; i++){ 96 printf("%lld\n",ans[i]); 97 } 98 } 99 return 0; 100 }
一个从很久以前就开始做的梦。
以上是关于Necklace HDU - 3874 (线段树/树状数组 + 离线处理)的主要内容,如果未能解决你的问题,请参考以下文章