HDU 3874 离线线段树

来源:互联网 发布:在淘宝买钢珠被警察查 编辑:程序博客网 时间:2024/04/28 05:41

统计区间内所有数字和,对于重复出现的只统计一次

线段树的离线算法 

按结束坐标排序,然后扫一遍,遇到重复的,就把之前插入线段树的给删掉

#include "stdio.h"#include "string.h"#include "algorithm"using namespace std;struct node{    int l,r;    __int64 sum;}data[200010];struct Mark{    int l,r,id;}mark[200010];int hash[1000001];__int64 a[50010],ans[200010];bool cmp(Mark a,Mark b){    return a.r<b.r;}void build (int l,int r,int k){    int mid;    data[k].l=l;    data[k].r=r;    data[k].sum=0;    if (l==r) return ;    mid=(l+r)/2;    build(l,mid,k*2);    build(mid+1,r,k*2+1);}void updata(int n,int k,int op){    int mid;    if (data[k].l==n && data[k].r==n)    {        data[k].sum+=op;        return ;    }    mid=(data[k].l+data[k].r)/2;    if (n<=mid) updata(n,k*2,op);    else updata(n,k*2+1,op);    data[k].sum=data[k*2].sum+data[k*2+1].sum;}__int64 query(int l,int r,int k){    int mid;    if (data[k].l==l && data[k].r==r)        return data[k].sum;    mid=(data[k].l+data[k].r)/2;    if (r<=mid) return query(l,r,k*2);    else        if (l>mid) return query(l,r,k*2+1);    else        return query(l,mid,k*2)+query(mid+1,r,k*2+1);}int main(){    int Case,i,n,m,now;    scanf("%d",&Case);    while (Case--)    {        scanf("%d",&n);        for (i=1;i<=n;i++)            scanf("%I64d",&a[i]);        scanf("%d",&m);        for (i=0;i<m;i++)        {            scanf("%d%d",&mark[i].l,&mark[i].r);            mark[i].id=i;        }        sort(mark,mark+m,cmp);        build(1,50000,1);        memset(hash,0,sizeof(hash));        now=1;        for (i=0;i<m;i++)        {            while (now<=mark[i].r)            {                if (hash[a[now]]!=0)                    updata(hash[a[now]],1,-a[now]);                hash[a[now]]=now;                updata(now,1,a[now]);                now++;            }            ans[mark[i].id]=query(mark[i].l,mark[i].r,1);        }        for (i=0;i<m;i++)            printf("%I64d\n",ans[i]);    }    return 0;}




1 0