hdu3333(线段树求不同数字之和)

本文介绍了一种解决区间求和问题的算法,特别适用于含有重复数字的情况。通过使用线段树数据结构,并结合排序和映射技巧,该算法能够高效地计算出不包含重复数字的区间和。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

普通的数组,普通的给区间求和,然而这道题要不同的数字,也就是如果有重复数字不能加入到和中


不能有重复数字那么给线段树中加一个数字,如果有重复的那之前的就要删掉

那么查区间的时候怎么办呢

在新的数字v[n]有效前把前n个数字和(需要查询的)先算出来

所以先给区间们排序,每次查之前构造范围内的线段树

//

//  main.cpp

//  3333

//

//  Created by Mr.Xue on 17/7/26.

//  Copyright © 2017 Mr.Xue. All rights reserved.

//


#include<iostream>

#include<cstdio>

#include<algorithm>

#include<map>


using namespace std;

map<long long,int> flag;

long long v[30005],sum[100005];

struct node

{

    int l,r;

    long long int val;

}a[120005];

struct nodee

{

    int l,r,id;

}f[100005];

bool cmp(nodee a,nodee b)

{

    return a.r<b.r;

}

void build(int l,int r,int i)

{

    a[i].l=l;

    a[i].r=r;

    a[i].val=0;

    if(l==r)

        return;

    int mid=(l+r)/2;

    build(l,mid,i*2);

    build(mid+1,r,i*2+1);

}

void insert(long long v,int id,int i)

{

    if(a[i].l==a[i].r&&a[i].l==id)

    {

        a[i].val=v;

        return;

    }

    int mid=(a[i].l+a[i].r)/2;

    if(id<=mid)

        insert(v,id,i*2);

    else

        insert(v,id,i*2+1);

    a[i].val=a[i*2].val+a[i*2+1].val;

}

long long int find(int l,int r,int i)

{

    if(a[i].l==l&&a[i].r==r)

        return a[i].val;

    int mid=(a[i].l+a[i].r)/2;

    if(mid>=r)

        return find(l,r,i*2);

    else if(mid<l)

        return find(l,r,i*2+1);

    else

        return find(l,mid,i*2)+find(mid+1,r,i*2+1);

}

int main()

{

    int t,n,m,l,r;

//long long sum;

    cin>>t;

    while(t--)

    {

        cin>>n;

        flag.clear();

        build(1,n,1);

        for(int i=1;i<=n;i++)

        {

            scanf("%lld",&v[i]);

            

            //

        }

        cin>>m;

        for(int i=0;i<m;i++)

        {

            scanf("%d %d",&f[i].l,&f[i].r);

            f[i].id=i;

           

        }

        sort(f,f+m,cmp);

        int ant=1;

        for(int i=0;i<m;i++)

        {

            while(ant<=f[i].r)

            {

                if(flag[v[ant]])

                    insert(0,flag[v[ant]],1);

                insert(v[ant],ant,1);

                flag[v[ant]]=ant;

                ant++;

                //for(int i=1;i<=2*n-1;i++)

                //    cout<<a[i].val<<' ';

                //cout<<endl;

            }

            sum[f[i].id]=find(f[i].l,f[i].r,1);

        }

        for(int i=0;i<m;i++)

            printf("%lld\n",sum[i]);

    }

    return 0;

}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值