HDU 3874 Necklace(树状数组 && 离线操作)

Necklace

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

【思路分析】
   该题的本质还是区间和的查询,可以用树状数组、线段树等处理。鉴于查询次数很多,所以考虑了离线操作。
   除了查询区间和之外,还加了一个去重的要求,也就是某一区间内的一个数只能被计算一次,如果有相同的则不再计入结果。这里可以定义两个数组pos[n]和pre[n],pos[i]用来记录i这个数在项链中的位置,pre[i]用来记录和i向前距离最近且数值相同的数的位置。
   首先,可以将pos数组全部赋值为-1,当读入一个数a[i]时有pre[i] = pos[a[i]],且更新a[i]最新的位置:pos[a[i]] = i,于是便建立了一个类似于链式前向星的结构。这样,在离线查询的时候便可以根据当前i位置的pre[i]是否为-1来判断其是否重复并进行更新区间操作了。

代码如下:
#include 
#include 
#include 
#include 
#include 
#include 
using namespace std;
typedef long long ll;
const int maxn = 51000;
const int maxm = 210000;
int n,m;
int a[maxn];
int pre[maxn],pos[1100000];
ll res[maxm],c[maxn];
struct Query
{
    int l,r;
    int id;
}query[maxm];
bool cmp(Query a,Query b)
{
    return a.r < b.r;
}
int lowbit(int x)
{
    return x & (-x);
}
ll sum(int i)
{
    ll ans = 0;
    while(i > 0)
    {
        ans += c[i];
        i -= lowbit(i);
    }
    return ans;
}
void add(int i,int w)
{
    while(i <= n)
    {
        c[i] += w;
        i += lowbit(i);
    }
}
void init()
{
    memset(pos,-1,sizeof(pos));
    memset(c,0,sizeof(c));
    scanf("%d",&n);
    for(int i = 1;i <= n;i++)
    {
        scanf("%d",&a[i]);
        add(i,a[i]);
        pre[i] = pos[a[i]];//pre记录与当前数相等的前面的数的位置
        pos[a[i]] = i;//pos更新a[i]这个数的位置
    }
    scanf("%d",&m);
    for(int i = 1;i <= m;i++)//记录以离线查询
    {
        scanf("%d %d",&query[i].l,&query[i].r);
        query[i].id = i;
    }
    sort(query + 1,query + m + 1,cmp);
}
void solve()
{
    int r = 0;
    for(int i = 1;i <= m;i++)
    {
        for(int j = r + 1;j <= query[i].r;j++)
        {
            if(pre[j] != -1)
            {
                add(pre[j],-a[j]);//去重
            }
        }
        r = query[i].r;
        res[query[i].id] = sum(query[i].r) - sum(query[i].l - 1);
    }
    for(int i = 1;i <= m;i++)
    {
        printf("%I64d\n",res[i]);
    }
}
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        init();
        solve();
    }
    return 0;
}


你可能感兴趣的:(ACM__高级数据结构)