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、付费专栏及课程。

余额充值