hdu 3333 树状数组

题意:给出一组序列,问某个区间内序列的和,跟普通求和不同的是,要求值相同的元素只能算一次。

树状数组 Or  线段树  :刚开始以为和前两道题目思路差不多,就考虑了考虑,离散化写了起来!!但中间突感有的数据没有处理!!于是考虑二分+离散处理query区间的数据!!!

于是乎:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=166612;///我数组开到30000+不对,在后面加一个0就对了。。表示想不清楚!
int t,n,m,a[maxn],b[maxn],pre[maxn],cnt;
__int64 A[maxn],c[maxn];
struct node
{
    int l,r,id;
}p[maxn];
int cmp(node a,node b)
{
    return a.r<=b.r;
}
int lowbit(int i)
{
    return (i&(-i));
}
void add(int i,int d)
{
    while(i<=n)
    {
        c[i]+=d;
        i+=lowbit(i);
    }
}
__int64 sum(int i)
{
    __int64 ret=0;
    while(i)
    {
        ret+=c[i];
        i-=lowbit(i);
    }
    return ret;
}
int bin(int idx,int num)
{
    int l=0,mid,r=num-1;
    while(l<=r)
    {
        mid=(l+r)>>1;
        if(a[mid]==idx)return mid;
        if(a[mid]>idx) r=mid-1;
        else l=mid+1;
    }
    return -1;
}
int main()
{
     int i,j,l,r;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d",&n);
        //memset(A,0,sizeof(A));
       // memset(c,0,sizeof(c));
       // memset(pre,0,sizeof(pre));
        for(i=0;i<=n;i++)A[i]=c[i]=0,pre[i]=0;
        cnt=0;
        for(i=1;i<=n;i++)
        {
            scanf("%d",&b[i]);
            a[cnt++]=b[i];
        }
        sort(a,a+cnt);
        cnt=unique(a,a+cnt)-a;
        scanf("%d",&m);
        for(i=1;i<=m;i++)
        {
            scanf("%d%d",&p[i].l,&p[i].r);
            p[i].id=i;
        }
        sort(p+1,p+m+1,cmp);
        for(j=1,i=1;i<=n;i++)
        {
            int id=bin(b[i],cnt);
            if(pre[id]) add(pre[id],-b[i]);
            add(i,b[i]); pre[id]=i;
            while(j<=m&&p[j].r==i)
            {
              A[p[j].id]=sum(p[j].r)-sum(p[j].l-1);
              j++;
            }
        }
        for(i=1;i<=m;i++)
        {
            printf("%I64d\n",A[i]);
        }
    }
    return 0;
}
/*
2
3
1 1 4
2
1 2
2 3
5
1 1 2 1 3
3
1 5
2 4
3 5
*/


 

 

你可能感兴趣的:(hdu 3333 树状数组)