HDU 3333 线段树+离散化

只查询区间不同的数的和(思路好题)

对查询离线

不断的往每个位置插值 并把前面位置的值置为0 每查到一个右端点 查询一下 (等价操作的转换)

离散化一下

#include<bits/stdc++.h>
#define Mem(a,b) memset(a,b,sizeof(a))
#define lson root<<1
#define rson root<<1|1
#define Mid int mid=(l+r)>>1
#define FREI freopen("in.txt","r",stdin)
#define N 30100
#define ll long long
using namespace std;
int n;
ll ans[N<<2];
map<ll,int> invf;
int a[N],pre[N];
ll f[N],res;
struct que{
    int l,r,id;
};
que q[100100];
ll sum[100100];
void lisanhua(int n){
    invf.clear();
    f[0]=0;
    int cnt=1;
    for(int i=1;i<=n;i++){
        if(!invf.count(a[i])){
            invf[a[i]]=cnt;
            f[cnt++]=a[i];
        }
    }
}
void update(int root,int l,int r,int ql,int qr,int val){
    if(l>qr||r<ql)
        return;
    if(r<=qr&&l>=ql){
        ans[root]=f[val];
        return;
    }
    Mid;
    update(lson,l,mid,ql,qr,val);
    update(rson,mid+1,r,ql,qr,val);
    ans[root]=ans[lson]+ans[rson];
}
void query(int root,int l,int r,int ql,int qr){
    if(l>qr||r<ql)
        return;
    if(r<=qr&&l>=ql){
        res+=ans[root];
        return;
    }
    Mid;
    query(lson,l,mid,ql,qr);
    query(rson,mid+1,r,ql,qr);
}
bool cmp(que a,que b){
    return a.r<b.r;
}
int main() {
    //FREI;
    int cas;
    for(scanf("%d",&cas);cas--;){
        int n;
        scanf("%d",&n);
        Mem(pre,0);
        Mem(ans,0);
        for(int i=1;i<=n;i++)
            scanf("%d",&a[i]);
        lisanhua(n);
        int m;
        scanf("%d",&m);
        for(int i=0;i<m;i++){
            scanf("%d%d",&q[i].l,&q[i].r);
            q[i].id=i;
        }
        sort(q,q+m,cmp);
        int cnt=0;
        for(int i=1;i<=n;i++){
            ll x=invf[a[i]];
            update(1,1,n,i,i,x);
            if(pre[x])
                update(1,1,n,pre[x],pre[x],0);
            pre[x]=i;
            while(q[cnt].r==i){
                res=0;
                query(1,1,n,q[cnt].l,q[cnt].r);
                sum[q[cnt++].id]=res;
            }
        }
        for(int i=0;i<m;i++)
            printf("%lld\n",sum[i]);
    }
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值