hdu3333(hash+树状数组)

来源:互联网 发布:阿里云免费半年 编辑:程序博客网 时间:2024/05/29 15:23

Turing Tree

Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 2578    Accepted Submission(s): 878


Problem Description
After inventing Turing Tree, 3xian always felt boring when solving problems about intervals, because Turing Tree could easily have the solution. As well, wily 3xian made lots of new problems about intervals. So, today, this sick thing happens again...

Now given a sequence of N numbers A1, A2, ..., AN and a number of Queries(i, j) (1≤i≤j≤N). For each Query(i, j), you are to caculate the sum of distinct values in the subsequence Ai, Ai+1, ..., Aj.
 

Input
The first line is an integer T (1 ≤ T ≤ 10), indecating the number of testcases below.
For each case, the input format will be like this:
* Line 1: N (1 ≤ N ≤ 30,000).
* Line 2: N integers A1, A2, ..., AN (0 ≤ Ai ≤ 1,000,000,000).
* Line 3: Q (1 ≤ Q ≤ 100,000), the number of Queries.
* Next Q lines: each line contains 2 integers i, j representing a Query (1 ≤ i ≤ j ≤ N).
 

Output
For each Query, print the sum of distinct values of the specified subsequence in one line.
 

Sample Input
231 1 421 22 351 1 2 1 331 52 43 5
 

Sample Output
15636
 
本题要求给定区间内不相同数的和,由于频繁地进行查询操作求区间很大,应用线段树,由于是求和操作,可以用树状数组代替线段树,在时间复杂度相同的情况下,树状数组比线段树编程简单,时间常数要小。
 
此题的重点不在这,关键在于处理不相同的数,很容易联想到hash,但看题目的数据0 ≤ Ai ≤ 1,000,000,000,开辟如此大的数组可能会超内存,即不能直接hash
又由于数据的个数1 ≤ N ≤ 30,000不大,可以考虑在此上做文章,即将数据离散化处理,将数据映射到一个新的数组,新数组存放不同数据的值,从而相同数据有着相同的下标,再通过下标构建hash表,hash数组开30,000,不会超内存。
 
为了解决这道题,在查询时必须删除重复元素,可以在来一个数Ai时,首先将其插在当前位置,再通过hash判断该数有无在此之前出现,若出现则通过hash表里的下表值找到并在之前出现位置删除该数。为了保证每次查询区间【a,b】内无重复数字,可以将查询区间存储起来,然后按右端点升序排列。在一个个将Ai插入树状数组,当元素下表i等于某个查询区间有端点时,计算该查询区间的和,由于排除了左边的重复元素,所以答案是正确的。
 
#include<iostream>#include<cstdio>#include<algorithm>using namespace std;const int MAX=30000+10;struct node{int s,e,ind;__int64 sum;}qu[100000+10];//s,e,ind分别表示区间端点和该询问的下标__int64 da[MAX];__int64 ta[MAX];__int64 C[MAX];int Lowbit[MAX];int visited[MAX];int cnt;bool cmp1(node a,node b){return a.e<b.e;}bool cmp2(node a,node b){return a.ind<b.ind;}__int64 QuerySum(int p)//查询原数组中下标1-p的元素的和 {    __int64 nSum = 0;    while( p > 0 )    {        nSum += C[p];       p -= Lowbit[p];    }     return nSum; } void Modify( int p,__int64 val) //原数组中下表为p的元素+val,导致C[]数组中部分元素值的改变{     while( p <= MAX )    {         C[p] += val;         p+=Lowbit[p];     } } int Binary_find(__int64 w){int l=1,r=cnt-1,mid;while(l<=r){mid=(l+r)>>1;if(ta[mid]<w)l=mid+1;else if(ta[mid]>w)r=mid-1;else {return mid;}}return 1;}int main(){int i,cas,n,q;for(i=1;i<=MAX;i++)Lowbit[i]=i&(-i);cin>>cas;while(cas--){scanf("%d",&n);for(i=1;i<=n;i++){scanf("%I64d",&da[i]);ta[i]=da[i];}cnt=1;sort(ta+1,ta+n+1);for(i=1;i<=n;i++){if(i==1||ta[i-1]!=ta[i])ta[cnt++]=ta[i];}scanf("%d",&q);for(i=1;i<=q;i++){scanf("%d%d",&qu[i].s,&qu[i].e);qu[i].ind=i,qu[i].sum=0;}sort(qu+1,qu+q+1,cmp1);memset(C,0,sizeof(C));memset(visited,0,sizeof(visited));int in,k=1;for(i=1;i<=n;i++){Modify(i,da[i]);in=Binary_find(da[i]);if(visited[in])Modify(visited[in],-da[i]);visited[in]=i;while(k<=q&&qu[k].e==i){qu[k].sum=QuerySum(qu[k].e)-QuerySum(qu[k].s-1);k++;}}sort(qu+1,qu+q+1,cmp2);for(i=1;i<=q;i++)printf("%I64d\n",qu[i].sum);}return 0;}

 
 
 
 
原创粉丝点击