Necklace(树状数组)

来源:互联网 发布:mac brew install m4 编辑:程序博客网 时间:2024/06/06 23:52

Necklace

Time Limit: 15000/5000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 5024    Accepted Submission(s): 1718


Problem Description
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.
 

Input
The 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.
 

Output
For each query, output a line contains an integer number, representing the result of the query.
 

Sample Input
261 2 3 4 3 531 23 52 661 1 1 2 3 531 12 43 5
 

Sample Output
3714136
 

Source
2011 Multi-University Training Contest 4 - Host by SDU
 

Recommend
lcy   |   We have carefully selected several similar problems for you:  3878 3875 3870 3877 3876

题意:

给你一串数字,然后有几个提问,每次给你一个区间的左端和右端,让你求这个区间内不重复的元素的和、

思路:

用树状数组来计算,开一个pre数组初始化为-1,既来判断一个数是否重复出现又可以记录重复出现的数的位置。开个loc数组存放每个元素的位置,还有就是必备的树状数组和输入数据的数组,然后开一个res数组来存放每一组查询的结果,在这里我们对区间的右端点进行由小到大排序,然后进行去重工作,这样前面的去重就不会影响后面的计算结果了。为了方便,我们建立一个结构体来存放区间左值右值以及他们是第几个出现的(即编号,便与输出)。

代码:

#include<iostream>#include<cstdio>#include<cstring>#include<algorithm>using namespace std;const int N=51000;const int M=210000;struct node{    int l,r;    int id;}q[M];int n,m,val[N],pre[N],loc[1100000];//val输入数据 ,pre用来记录某个数字是否只有一个,loc 是位置 long long arr[N],res[M];//arr树状数组 ,res存放每次询问的结果 int lowbit(int x){    return x&(-x);}void update(int i,int x){    while(i<=n){        arr[i]+=x;        i+=lowbit(i);    }}long long Sum(int i){    long long ans=0;    while(i>0){        ans+=arr[i];        i-=lowbit(i);    }    return ans;}bool cmp(node a,node b){  //按区间右端点进行排序     return a.r<b.r;}int main(){    //freopen("input.txt","r",stdin);    int t;    scanf("%d",&t);    while(t--){        memset(arr,0,sizeof(arr));        memset(loc,-1,sizeof(loc));        scanf("%d",&n);        for(int i=1;i<=n;i++){            scanf("%d",&val[i]);            pre[i]=loc[val[i]];   //记录是否重复出现过              loc[val[i]]=i;       //记录存在的位置             update(i,val[i]);        }        scanf("%d",&m);        for(int i=1;i<=m;i++)   //输入m次询问 {            scanf("%d%d",&q[i].l,&q[i].r);            q[i].id=i;        }        sort(q+1,q+1+m,cmp);//按照区间右边由小到大进行排序         int r=0;  //临时存储编号         for(int i=1;i<=m;i++){            for(int j=r+1;j<=q[i].r;j++)                if(pre[j]!=-1)     //减去重复的值                     update(pre[j],-val[j]);            r=q[i].r;            res[q[i].id]=Sum(q[i].r)-Sum(q[i].l-1);        }        for(int i=1;i<=m;i++)            printf("%I64d\n",res[i]);    }    return 0;}



原创粉丝点击