HDU 3333-Turing Tree-线段树+离散+离线

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

题目大意:

线段树的区间查询,查询区间内不同数值的数的和。

核心思想:

将数值离散化后记录每个数值a[i]最近一次出现的位置pre[a[i]]。
将查询离线处理,按查询区间的右端点排序,遍历原数组,依次进树,每进入一个数a[i],就将位置pre[a[i]]上的数清零,并更新pre[a[i]]=i。

代码如下:

#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
const int N=3e4+20,Q=1e5+20;
ll a[N],b[N];
int pre[N],cnt;
struct tnode{
    int l,r,id;
    ll chu;
}que[Q];
struct node{
    int l,r;
    ll sum;
}tr[N<<2];
void pushup(int m)
{
    tr[m].sum=tr[m<<1].sum+tr[m<<1|1].sum;
    return;
}
void build(int m,int l,int r)
{
    tr[m].l=l;
    tr[m].r=r;
    if(l==r)
    {
        tr[m].sum=0;
        return;
    }
    int mid=(l+r)>>1;
    build(m<<1,l,mid);
    build(m<<1|1,mid+1,r);
    pushup(m);
    return;
}
void update(int m,int x,ll v)
{
    if(tr[m].l==x&&tr[m].r==x)
    {
        tr[m].sum=v;
        return;
    }
    int mid=(tr[m].l+tr[m].r)>>1;
    if(x<=mid)
        update(m<<1,x,v);
    else
        update(m<<1|1,x,v);
    pushup(m);
    return;
}
ll query(int m,int l,int r)
{
    if(tr[m].l==l&&tr[m].r==r)
        return tr[m].sum;
    int mid=(tr[m].l+tr[m].r)>>1;
    if(r<=mid)
        return query(m<<1,l,r);
    if(l>mid)
        return query(m<<1|1,l,r);
    return query(m<<1,l,mid)+query(m<<1|1,mid+1,r);
}
bool cmp1(tnode x,tnode y)
{
    return x.r<y.r;
}
bool cmp2(tnode x,tnode y)
{
    return x.id<y.id;
}
int getid(ll x)
{
    return lower_bound(b+1,b+cnt,x)-b;
}
int main()
{
    int T;
    cin>>T;
    while(T--)
    {
        int n,q;
        cnt=1;
        //输入
        scanf("%d",&n);
        for(int i=1;i<=n;i++)
            pre[i]=0;
        a[0]=-1;
        for(int i=1;i<=n;i++)
            scanf("%lld",&a[i]);
        //离散化
        sort(a+1,a+1+n);
        for(int i=1;i<=n;i++)
            if(a[i]!=a[i-1])
                b[cnt++]=a[i];
        //建树
        build(1,1,n);
        //离线处理
        scanf("%d",&q);
        for(int i=1;i<=q;i++)
        {
            scanf("%d%d",&que[i].l,&que[i].r);
            que[i].id=i;
        }
        sort(que+1,que+1+q,cmp1);
        que[0].r=0;
        //更新和查询同时进行
        for(int i=1;i<=q;i++)
        {
            for(int j=que[i-1].r+1;j<=que[i].r;j++)
            {
                int z=getid(a[j]);
                if(pre[z])
                    update(1,pre[z],0);
                update(1,j,a[j]);
                pre[z]=j;
            }
            que[i].chu=query(1,que[i].l,que[i].r);
        }
        sort(que+1,que+1+q,cmp2);
        //输出
        for(int i=1;i<=q;i++)
            printf("%lld\n",que[i].chu);
    }
    return 0;
}

原文地址:https://www.cnblogs.com/NothingbutFight/p/11307358.html

时间: 2024-10-19 05:41:57

HDU 3333-Turing Tree-线段树+离散+离线的相关文章

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(树状数组 || 线段树)

题意:给定一个区间,q个查询,对于每次查询回答这个区间内所有不重复的数的和. 思路:可以考虑使用树状数组来做. 先读入所有查询,离线来做,将所有查询按右端点升序排序. 那么我们从给定区间的第一个元素开始遍历这个区间,在此过程中更新每一个元素上一次出现的位置,每次将现在位置加上a[i]并将lastpos位置减去a[i], 也就是说,我们每一步都是保留与当前位置距离最近的重复元素值,其余置零,那么这样肯定能保证答案正确, 如果遍历到的这个位置恰好是一个询问的右端点,那么我们输出修改后的区间值之和.

HDU 3333 Turing Tree (主席树)

题意:给定上一个序列,然后有一些询问,求区间 l - r 中有多少个不同的数的和. 析:和求区间不同数的方法是一样,只要用主席树维护就好. 代码如下: #pragma comment(linker, "/STACK:1024000000,1024000000") #include <cstdio> #include <string> #include <cstdlib> #include <cmath> #include <iost

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

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

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 3333 Turing Tree (离线询问+线段树)

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

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