1. 程式人生 > >Necklace HDU - 3874 (線段樹/樹狀數組 + 離線處理)

Necklace HDU - 3874 (線段樹/樹狀數組 + 離線處理)

技術 現在 fin () panel none open ant utf

Necklace HDU - 3874 Mery has a beautiful necklace. The necklace is made up of N magic balls. Each ball has a beautiful value. The balls with the same beautiful value look the same, so if two or more balls have the same beautiful value, we just count it once. We define the beautiful value of some interval [x,y] as F(x,y). F(x,y) is calculated as the sum of the beautiful value from the xth ball to the yth ball and the same value is ONLY COUNTED ONCE. For example, if the necklace is 1 1 1 2 3 1, we have F(1,3)=1, F(2,4)=3, F(2,6)=6.

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 (線段樹/樹狀數組 + 離線處理)