Turing Tree(树状数组+离散化)

Turing Tree

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


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
  
  
2 3 1 1 4 2 1 2 2 3 5 1 1 2 1 3 3 1 5 2 4 3 5
 

Sample Output
  
  
1 5 6 3 6
 

Author
3xian@GDUT
 

Source
 

Recommend
lcy   |   We have carefully selected several similar problems for you:   1542  3397  1698  1394  1540

题意:

和前面说的Necklace一样,只不过数据大了。需要进行离散化操作。

思路:

树状数组离散化这里运用stl对数据进行离散,其实离散的目的就是为了后面方便记录这个数字是否出现过,如果不离散,数据非常大,那么数组就会发生越界。



关于lower_bound()函数的总结:

函数lower_bound()在first和last中的前闭后开区间进行二分查找,返回大于或等于val的第一个元素位置。如果所有元素都小于val,则返回last的位置

举例如下:

一个数组number序列为:4,10,11,30,69,70,96,100.设要插入数字3,9,111.pos为要插入的位置的下标

pos = lower_bound( number, number + 8, 3) - number,pos = 0.即number数组的下标为0的位置。

pos = lower_bound( number, number + 8, 9) - number, pos = 1,即number数组的下标为1的位置(即10所在的位置)。

pos = lower_bound( number, number + 8, 111) - number, pos = 8,即number数组的下标为8的位置(但下标上限为7,所以返回最后一个元素的下一个元素)。

所以,要记住:函数lower_bound()在first和last中的前闭后开区间进行二分查找,返回大于或等于val的第一个元素位置。如果所有元素都小于val,则返回last的位置,且last的位置是越界的!!~

返回查找元素的第一个可安插位置,也就是“元素值>=查找值”的第一个元素的位置

代码:

#include<iostream>
#include<string>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<iomanip>
#include<queue>
#include<cstring>
#include<map>
using namespace std;
typedef long long ll;
int n,m;
ll tree[30005],ans[100005];   //树状数组和记录结果的数组
int a[30005],vis[30005],b[30005],pos[30005];//vis表示是否出现过,
struct node{
    int s,e,id;
    bool operator <(const node& b) const   //排序
    {
        return e<b.e||(e==b.e&&s<b.s);
    }
}p[100005];
int lowbit(int i)
{
    return i&(-i);
}
void add(int i,int v)
{
    while(i<=n)
    {
        tree[i]+=v;
        i+=lowbit(i);
    }
}
ll sum(int i)
{
    ll res=0;
    while(i>0)
    {
        res+=tree[i];
        i-=lowbit(i);
    }
    return res;
}
int main()
{
    int i,T;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d",&n);
        memset(tree,0,sizeof(tree));
        memset(vis,0,sizeof(vis));
        for(i=1;i<=n;i++)
        {
            scanf("%d",&a[i]);
            b[i]=a[i];
        }
        scanf("%d",&m);
        for(i=1;i<=m;i++)
        {
            scanf("%d%d",&p[i].s,&p[i].e);
            p[i].id=i;
        }
        sort(p+1,p+m+1);
        sort(b+1,b+n+1);
        for(i=1;i<=n;i++)
        {
            pos[i]=lower_bound(b+1,b+n+1,a[i])-b;
        }
        int it=1;
        for(i=1;i<=m;i++)
        {
            while(it<=p[i].e)    //去重,因为对右区间由小到大排序了。所以去重不会对后面产生影响
 {
                if(vis[pos[it]]!=0)
                {
                    add(vis[pos[it]],-a[it]);  //离散的作用体现在这
                }
                vis[pos[it]]=it;
                add(it,a[it]);
                it++;
            }
            ans[p[i].id]=sum(p[i].e)-sum(p[i].s-1);
        }
        for(i=1;i<=m;i++)
        {
            printf("%I64d\n",ans[i]);
        }
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值