HDU-3333-Turing Tree

题目

现在给定一个N个数的序列A1 A2…,和大量的查询(i,j)(j 1≤≤≤N)。对于每个查询(i, j),你要计算子序列Ai, Ai+1,…Aj。——重复的数只能算一次。

输入

第一行是一个整数T(1≤T≤10),indecating以下测试点的数量。
对于每种情况,输入格式如下:
1:N(1≤N≤30000)。
第2行:N个整数A1, A2,…,一个Ai(0≤≤1000000000)。
3行:Q Q(1≤≤100000),查询的数量。
接下来问:每一行包含2整数,j代表一个查询(j 1≤≤≤N)。

输出

对于每个查询,在一行中打印指定子序列的不同值的和。

题解:
因为不允许重复 所以需要有清0操作。边插入(update),清零(update)。边询问。
离线处理多次询问。离散化处理Ai 以便存入到vis[],dex[]中。
将区间的右端点从小到大将区间排序。比如序列 1 3 3 2 3。查询(2,3) ; (3,5)。
查询(2,3)在插入1 3 3 的时候插入第二个3的时候就会把第一个3清0。插入 2 3时会把第二个3清0。
假如先查询 (3,5)。会在第一次查询时把第一个第二个3都清0。无法查询(2,3)。

#include <cstring>
#include <iostream>
#include <algorithm>
#include <cstdio>
#define  m(a,b) memset(a,b,sizeof a)
typedef long long ll;
using namespace std;
const int N=30005*4;
ll ans[N],cur[N],tmp[N],fin[N],dex[N];//ans 线段树里面的数组 cur数据值 tmp排序后的数据值以便reflect fin储存询问的答案
bool vis[N];//判断当前状态下 i 所映射的数是否出现在线段树里面.若出现,则出现的位置是 dex[i] 这里都将采用了离散化了
struct interval
{
    int l,r,id;    //离线处理多次询问 把需要的区间按右端点从小到大排序 区间打乱 故需要一个id.
}span[N];          // span[i].id为是这一次的询问  fin[span[i].id]即为所求、
bool cmp(interval a,interval b)
{
    return a.r<b.r;
}
ll query(int cl,int cr,int l,int r,int pos)
{
    if(cl<=l&&r<=cr)
        return ans[pos];
    int mid=(l+r)>>1;
    ll ans=0;
    if(cl<=mid)
        ans+=query(cl,cr,l,mid,pos<<1);
    if(cr>mid)
        ans+=query(cl,cr,mid+1,r,pos<<1|1);
    return ans;
}
void update(int n,ll val,int l,int r,int pos)
{
    if(l==r)
    {
        ans[pos]=val;
        return;
    }
    int mid=(l+r)>>1;
    if(n<=mid)
        update(n,val,l,mid,pos<<1);
    else
        update(n,val,mid+1,r,pos<<1|1);
    ans[pos]=ans[pos<<1]+ans[pos<<1|1];
}
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        m(vis,0);
        int n,m;
        scanf("%d",&n);
        for(int i=1;i<=n;i++)
            scanf("%lld",&cur[i]),tmp[i]=cur[i];//添加一个数的时候需要判断他是否已经在线段树里面,故要有vis[],假如有的话dex[]为这个数存在的位置
        sort(tmp+1,tmp+n+1);             //是为了 将超级大的数用他在tmp数组排序后的位置reflect。
        scanf("%d",&m);
        for(int i=1;i<=m;i++)            //用lower_bound()函数正好可以去重啊。。因为多个数映射到同一位置。肯定是这些数一样啊
            scanf("%d%d",&span[i].l,&span[i].r),span[i].id=i;
        sort(span+1,span+m+1,cmp);
        int j=1;
        for(int i=1;i<=n;i++)
        {
            int refl=lower_bound(tmp+1,tmp+n+1,cur[i])-(tmp+1);
            if(!vis[refl])
            {
                vis[refl]=1;
                update(i,cur[i],1,n,1);
                dex[refl]=i;
            }
            else
            {
                update(dex[refl],0,1,n,1);
                update(i,cur[i],1,n,1);
                dex[refl]=i;
            }
            for(;j<=m;j++)
            {
                if(i!=span[j].r)
                    break;
                fin[span[j].id]=query(span[j].l,span[j].r,1,n,1);
            }
        }
        for(int i=1;i<=m;i++)
            printf("%lld\n",fin[i]);
    }
}

猜你喜欢

转载自blog.csdn.net/qq_42576687/article/details/87879996
今日推荐