HDU 3333 Turing Tree(离线线段树)

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

题意:求给定区间内不同值的和,重复的计算一次。。询问Q<=100000,考虑离线

做法。将所有的询问保存下来,按照右端点由小到大排序。跟新小于p[i].r的值,对

值进行hash,保存值的位置,相同时,原位置上值更新为0,此值的位置更新的当前位置。。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<map>
typedef long long LL;
using namespace std;
#define REPF( i , a , b ) for ( int i = a ; i <= b ; ++ i )
#define REP( i , n ) for ( int i = 0 ; i < n ; ++ i )
#define CLEAR( a , x ) memset ( a , x , sizeof a )
const int maxn=30005;
const int maxm=100005;
LL sum[maxn<<2],a[maxn],ans[maxm];
struct node{
    int l,r,index;
    bool operator<(const node a)const
    {
        return r<a.r;
    }
}p[maxm];//保存每次询问
map<LL,int>hash;
int t,n,m;
void pushup(int rs)
{
    sum[rs]=sum[rs<<1]+sum[rs<<1|1];
}
void build(int rs,int l,int r)
{
    sum[rs]=0;
    if(l==r)   return ;
    int mid=(l+r)>>1;
    build(rs<<1,l,mid);
    build(rs<<1|1,mid+1,r);
}
void update(int rs,LL c,int x,int l,int r)
{
    if(l==r)
    {
        sum[rs]=c;
        return ;
    }
    int mid=(l+r)>>1;
    if(x<=mid)   update(rs<<1,c,x,l,mid);
    else   update(rs<<1|1,c,x,mid+1,r);
    pushup(rs);
}
LL query(int rs,int x,int y,int l,int r)
{
    if(l>=x&&r<=y)
        return sum[rs];
    int mid=(l+r)>>1;
    LL res=0;
    if(x<=mid)  res+=query(rs<<1,x,y,l,mid);
    if(y>mid)   res+=query(rs<<1|1,x,y,mid+1,r);
    return res;
}
void solve()
{
    int pos=1;
    REPF(i,1,m)
    {
        while(p[i].r>=pos)
        {
            if(hash[a[pos]])//若此值出现过,原位置上值更新为0.
                update(1,0,hash[a[pos]],1,n);
            hash[a[pos]]=pos;//更新当前值的位置
            update(1,a[pos],pos,1,n);pos++;
        }
//        cout<<"666   "<<query(1,1,2,1,n)<<endl;
        ans[p[i].index]=query(1,p[i].l,p[i].r,1,n);
    }
}
int main()
{
     scanf("%d",&t);
     int x,y;
     while(t--)
     {
         hash.clear();
         scanf("%d",&n);
         build(1,1,n);
         REPF(i,1,n)  scanf("%I64d",&a[i]);
         scanf("%d",&m);
         REPF(i,1,m)
         {
             scanf("%d%d",&p[i].l,&p[i].r);
             p[i].index=i;
         }
         sort(p+1,p+1+m);
         solve();
         REPF(i,1,m)
            printf("%I64d\n",ans[i]);
     }
     return 0;
}
时间: 2024-10-23 20:53:44

HDU 3333 Turing Tree(离线线段树)的相关文章

HDU 3333 Turing Tree (离线询问+线段树)

题目地址:HDU 3333 将询问离线保存下来,然后将数组的点离散化,记录每个值上一次出现的位置.然后枚举数组的数,若当前枚举的数前面出现过,那么就删掉前面出现过的那个位置上的数,更新当前这个位置上的数,然后那些所有询问的右端点为当前位置的就可以通过查询来得到结果了. 更新与查询用线段树来优化. 代码如下: #include <iostream> #include <string.h> #include <math.h> #include <queue> #

HDU 3333 Turing Tree 树状数组 离线查询

题意: 给你一个数列,然后有n个查询,问你给定区间中不同数字的和是多少. 思路还是比较难想的,起码对于蒟蒻我来说. 将区间按照先右端点,后左端点从小到大排序之后,对于每个查询,我只要维护每个数字出现的最后一次就可以了(这个结论稍微想一下就可以证明是正确的). 然后就是简单的点更新,区间求和问题了- #include <cstdio> #include <cstring> #include <iostream> #include <map> #include

hdu 3333 Turing Tree(线段树)

题目链接:hdu 3333 Turing Tree 题目大意:给定一个长度为N的序列,有M次查询,每次查询l,r之间元素的总和,相同元素只算一次. 解题思路:涨姿势了,线段树的一种题型,离线操作,将查询按照右区间排序,每次考虑一个询问,将mv ~ r的点全部标记为存在,并且对于每个位置i,如果A[i]在前面已经出现过了,那么将前面的那个位置减掉A[i],当前位置添加A[i],这样做维护了每个数尽量做,那么碰到查询,用sum[r] - sum[l-1]即可. #include <cstdio>

HDU 3333 Turing Tree(树状数组离线处理)

HDU 3333 Turing Tree 题目链接 题意:给定一个数组,每次询问一个区间,求出这个区间不同数字的和 思路:树状数组离线处理,把询问按右端点判序,然后用一个map记录下每个数字最右出现的位置,因为一个数字在最右边出现,左边那些数字等于没用了,利用树状数组进行单点修改区间查询即可 代码: #include <cstdio> #include <cstring> #include <algorithm> #include <map> using n

HDU 3333 Turing Tree (离散化+离线处理+树状数组)

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 t

HDU 4417 Super Mario(离线线段树or树状数组)

Problem Description Mario is world-famous plumber. His "burly" figure and amazing jumping ability reminded in our memory. Now the poor princess is in trouble again and Mario needs to save his lover. We regard the road to the boss's castle as a l

hdu 3333 Turing Tree (树状数组+离线处理+离散化)

Turing Tree Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 3981    Accepted Submission(s): 1349 Problem Description After inventing Turing Tree, 3xian always felt boring when solving problems a

HDU 3333 Turing Tree(离线树状数组)

Turing Tree Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 5014    Accepted Submission(s): 1777 Problem Description After inventing Turing Tree, 3xian always felt boring when solving problems

hdu 3333 Turing Tree(树状数组离线操作)

Turing Tree Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 3904    Accepted Submission(s): 1325 Problem Description After inventing Turing Tree, 3xian always felt boring when solving problems