HDU 3874 Necklace(树状数组+离线处理)

HDU 3874 Necklace(树状数组+离线处理)

http://acm.hdu.edu.cn/showproblem.php?pid=3874

题意:

        有一个由n个整数组成的数列,要求你回答以下询问[L,R]:返回a[L]到a[R]的和。但是其中相同值的元素只能计算一次。比如数列1 1 1 2 3 4 ,如果我们求[1,3]的和,就返回1。如果我们求[2,4]的和,就返回3。

分析:

        预处理:首先我们需要一个树状数组A[n],我们从左到右读入所有的a[i],如果当前a[i]=x值是第一次出现,就执行add(i,x),否则不执行。当我们扫描完了n个值后,我们保证sum(R)就是区间[1,R]的答案(想想是不是)。

       接下来我们对所有查询的区间进行排序,使得[L,R]区间中L小的区间排在前面。我们首先用sum(R)给出所有区间[1,R]的查询。

        接着我们要计算所有区间[2,R]的查询,但是做这步前,我们还需要消除a[1]对后面序列的影响,使得我们这个序列就好像是本来就是从a[1]开始的,从来没有存在过a[1]。要完成这个要求,我们只需要执行add(1,-a[1])并且我们需要找到a[1]值第二次出现的位置y执行add(y,a[1])。OK做完上面这步我们就保证了当前的sum(R)就是区间[2,R]的答案(有关区间[3,R],[4,R]等的查询我们目前不管,以后再说)。

        所以每当我们查询完了区间[i-1,R]的答案后,我们需要做的操作是:

        找到a[i-1]的值出现的下一个位置y(如果不存在为-1时,就默认为n+1位置),执行add(i-1,-a[i-1]) 和 add(y,a[i-1])即可。

        我们用next[i]=j来表示与a[i]值相同的下一个值出现在j位置。用hash[h]=i表示值为h的a[i]第一次出现的位置是i。

        答案可能超过int 需要用long long

AC代码:1640ms一次AC

#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int MAXN=50000+1000;
const int MAXV=1000000+100;
const int MAXM=200000+1000;
struct HASHMAP
{
    int head[MAXV];//head[x]=i表示第一个出现的x值下标是i
    int next[MAXN];
    int size;
    void init()
    {
        memset(head,-1,sizeof(head));
    }
    void insert(int i,int v)//将a[i]=v插入到HASHMAP中
    {
        next[i]=-1;
        if(head[v]==-1)
            head[v]=i;
        else
        {
            int j=head[v];
            while(next[j]!=-1)
                j=next[j];
            next[j]=i;
        }
    }
    int find(int i)//找到a[i]值下一次出现的位置
    {
        return next[i];
    }
}hm;
long long c[MAXN];
int a[MAXN];//初始读入的值
struct node
{
    int l,r;
    int index;
    bool operator <(const node&b)const
    {
        return l<b.l;
    }
}nodes[MAXM];//查询命令
long long ans[MAXM];//最终答案
int lowbit(int x)
{
    return x&(-x);
}
long long sum(int x)
{
    long long res=0;
    while(x)
    {
        res +=c[x];
        x-=lowbit(x);
    }
    return res;
}
void add(int x,int v)
{
    while(x<MAXN)
    {
        c[x]+=v;
        x+=lowbit(x);
    }
}

int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        int n,m;
        scanf("%d",&n);
        hm.init();
        memset(c,0,sizeof(c));
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&a[i]);
            if(hm.head[a[i]]==-1)//目前不存在a[i]值
                add(i,a[i]);
            hm.insert(i,a[i]);
        }

        scanf("%d",&m);
        for(int i=1;i<=m;i++)
        {
            scanf("%d%d",&nodes[i].l,&nodes[i].r);
            nodes[i].index=i;
        }
        sort(nodes+1,nodes+m+1);

        int j=1;//表示当前处理第j个排序后的区间
        for(int i=1;i<=n;i++)//从区间[i,R]一一处理
        {
            while(nodes[j].l==i)
            {
                ans[nodes[j].index]=sum(nodes[j].r);
                j++;
            }
            if(j>m)
                break;
            add(i,-a[i]);
            int next_ai=hm.find(i);
            if(next_ai!=-1)
                add(next_ai,a[i]);
        }
        for(int i=1;i<=m;i++)
            printf("%I64d\n",ans[i]);
    }
    return 0;
}



  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
资源包主要包含以下内容: ASP项目源码:每个资源包中都包含完整的ASP项目源码,这些源码采用了经典的ASP技术开发,结构清晰、注释详细,帮助用户轻松理解整个项目的逻辑和实现方式。通过这些源码,用户可以学习到ASP的基本语法、服务器端脚本编写方法、数据库操作、用户权限管理等关键技术。 数据库设计文件:为了方便用户更好地理解系统的后台逻辑,每个项目中都附带了完整的数据库设计文件。这些文件通常包括数据库结构图、数据表设计文档,以及示例数据SQL脚本。用户可以通过这些文件快速搭建项目所需的数据库环境,并了解各个数据表之间的关系和作用。 详细的开发文档:每个资源包都附有详细的开发文档,文档内容包括项目背景介绍、功能模块说明、系统流程图、用户界面设计以及关键代码解析等。这些文档为用户提供了深入的学习材料,使得即便是从零开始的开发者也能逐步掌握项目开发的全过程。 项目演示与使用指南:为帮助用户更好地理解和使用这些ASP项目,每个资源包中都包含项目的演示文件和使用指南。演示文件通常以视频或图文形式展示项目的主要功能和操作流程,使用指南则详细说明了如何配置开发环境、部署项目以及常见问题的解决方法。 毕业设计参考:对于正在准备毕业设计的学生来说,这些资源包是绝佳的参考材料。每个项目不仅功能完善、结构清晰,还符合常见的毕业设计要求和标准。通过这些项目,学生可以学习到如何从零开始构建一个完整的Web系统,并积累丰富的项目经验。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值