hdu 3333 线段树离线操作

hdu 3333 线段树离线操作    

题目大意:求解区间内不同数字的和

显然,要先按照查询区间的右值进行排序。然后进行数据插入,把每个数放进线段树的时候,先判断再之前他有没有在线段树,如果在,则删除它,并把他的位置更新到当前点。

#include<stdio.h>  

#include<string.h>  

#include<algorithm>  

#include<map>  

using namespace std;  

typedef __int64 ll;  

#define N 300010  

#define M 100010  

struct   

{  

    int l,r;  

    ll num;  

}root[N*4];  

struct Q  

{  

    int s,t,ind;  

}q[M];  

bool cmp(Q i,Q j)  

{  

    return i.t<j.t;  

}  

inline void build(int t,int x,int y)  

{  

    root[t].l=x;  

    root[t].r=y;  

    root[t].num=0;  

    if(x==y) return;  

    int m=(x+y)>>1;  

    build(t*2,x,m);  

    build(t*2+1,m+1,y);  

}  

inline void Modefiy(int t,int x,ll val)  

{  

    int l=root[t].l;  

    int r=root[t].r;  

    if(l==r)  

    {  

        root[t].num+=val;return;  

    }  

    int m=(l+r)>>1;  

    if(x<=m) Modefiy(t*2,x,val);  

    else Modefiy(t*2+1,x,val);  

    root[t].num=root[t*2].num+root[t*2+1].num;  

}  

inline ll query(int t,int x,int y)  

{  

    int l=root[t].l;  

    int r=root[t].r;  

    if(l==x&&r==y)  

    {  

        return root[t].num;  

    }  

    int m=(l+r)>>1;  

    ll ans=0;  

    if(x<=m) ans+=query(t*2,x,min(m,y));  

    if(y>m) ans+=query(t*2+1,max(m+1,x),y);  

    return ans;  

}  

  

int t,n,qn;  

ll a[N];  

map<ll,int>m;  

ll ans[M];  

int main()  

{  

    scanf("%d",&t);  

    while(t--)  

    {  

        m.clear();  

        scanf("%d",&n);  

        for(int i=1;i<=n;i++) scanf("%I64d",&a[i]);  

        build(1,1,n);  

        scanf("%d",&qn);  

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

        {  

            scanf("%d%d",&q[i].s,&q[i].t);  

            q[i].ind=i;  

        }  

        sort(q,q+qn,cmp);  

        int k=1;  

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

        {  

            for(;k<=q[i].t;k++)  

            {  

                if(m[a[k]]!=0) Modefiy(1,m[a[k]],-a[k]);  

                m[a[k]]=k;  

                Modefiy(1,k,a[k]);  

            }  

            ans[q[i].ind]=query(1,q[i].s,q[i].t);  

        }  

        for(int i=0;i<qn;i++) printf("%I64d\n",ans[i]);  

    }  

    return 0;  

}  

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值