HDU 3874 Necklace(线段树啊 单点更新 区间求和)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3874


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
   
   
   
   
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
 

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

题意:

求给出的每个区间的和,注意所求区间里相同的数只计算一次!

例如:1 1 1 2 3 1, F(1,3)=1, F(2,4)=3, F(2,6)=6.

PS:

离线算法:先按询问的右端点排序,然后依次把数字插入到线段树里,用pre[i]记录数字  i 上一次出现的位置,如果 i 已经出现过,删除之前的,并且添加到当前的位置。遇到可以处理的询问则处理,同时存储结果。

代码如下:

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define lson l , mid , rt << 1
#define rson mid + 1 , r , rt << 1 | 1
#define LL __int64
const int maxn = 111111;
LL add[maxn<<2];//用来标记每个节点,为0则表示没有标记,否则为标记;
LL sum[maxn<<2];//求和
struct node
{
    int l, r;
    int id;
    bool operator < (const node &a)const
    {
        return r < a.r;
    }
} e[maxn<<1];
void PushUp(int rt) //把当前结点的信息更新到父结点
{

    sum[rt] = sum[rt<<1] + sum[rt<<1|1];
}

void build(int l,int r,int rt)
{
    add[rt] = 0;//初始化为所有结点未被标记
    sum[rt] = 0;
    if(l == r)
    {
        //scanf("%lld",&sum[rt]);
        return ;
    }
    int mid = (l + r) >> 1;
    build(lson);
    build(rson);
    PushUp(rt);
}
void update(int p,int sc,int l,int r,int rt)
{
    if(l == r) //叶节点
    {
        sum[rt] = sc;
        return ;
    }
    int mid = (l + r) >> 1;
    if(p <= mid)//递归更新左子树或者右子树
        update(p , sc , lson);
    else
        update(p , sc , rson);
    PushUp(rt);
}
LL query(int L,int R,int l,int r,int rt)
{
    if(L <= l && r <= R)
    {
        return sum[rt];
    }

    int mid = (l + r) >> 1;
    LL ret = 0;
    if (L <= mid)
        ret += query(L , R , lson);
    if (mid < R)
        ret += query(L , R , rson);
    return ret;
}
int pre[1000010], a[maxn];
LL ans[maxn<<1];
int main()
{
    int N , Q;
    int t;
    scanf("%d",&t);
    while(t--)
    {
        memset(pre,-1,sizeof(pre));
        scanf("%d",&N);//N为节点数
        for(int i = 1; i <= N; i++)
        {
            scanf("%d",&a[i]);
        }
        build(1, N, 1); //建树
        scanf("%d",&Q);
        for(int i = 1; i <= Q; i++)
        {
            scanf("%d%d",&e[i].l,&e[i].r);
            e[i].id = i;
        }
        sort(e+1, e+Q+1);
        for(int i=1, j=1; i<=N && j<=Q; i++)
        {
            if(pre[a[i]]!=-1)
                update(pre[a[i]],0,1,N,1);
            update(i,a[i],1,N,1);//把i的成绩更为a[i]
            while(j<=Q && e[j].r<=i)
            {
                if(e[j].r == i)
                    ans[e[j].id]=query(e[j].l,e[j].r,1,N,1);
                j++;
            }
            pre[a[i]]=i;
        }
        for(int i = 1; i <= Q; i++)
        {
            printf("%I64d\n",ans[i]);
        }
    }
    return 0;
}
/*
2
6
1 2 3 4 3 5
3
1 2
2 6
3 5
6
1 1 1 2 3 5
3
1 1
2 4
3 5
*/


你可能感兴趣的:(线段树,HDU)