HDU 3333 Turing Tree (离线询问+线段树)

题目地址:HDU 3333
将询问离线保存下来,然后将数组的点离散化,记录每个值上一次出现的位置。然后枚举数组的数,若当前枚举的数前面出现过,那么就删掉前面出现过的那个位置上的数,更新当前这个位置上的数,然后那些所有询问的右端点为当前位置的就可以通过查询来得到结果了。
更新与查询用线段树来优化。
代码如下:

#include <iostream>
#include <string.h>
#include <math.h>
#include <queue>
#include <algorithm>
#include <stdlib.h>
#include <map>
#include <set>
#include <stdio.h>
using namespace std;
#define LL long long
#define pi acos(-1.0)
#pragma comment(linker, "/STACK:1024000000,1024000000")
const int mod=1e9+7;
const int INF=0x3f3f3f3f;
const double eqs=1e-3;
const int MAXN=30000+10;
#define root 0, n-1, 1
#define lson l, mid, rt<<1
#define rson mid+1, r, rt<<1|1
struct node
{
        int l, r, id;
        LL ans;
}qu[MAXN<<2];
int a[MAXN], c[MAXN], b[MAXN], pos[MAXN], cnt;
LL sum[MAXN<<2];
int BS(int x)
{
        int low=0, high=cnt-1, mid;
        while(low<=high){
                mid=low+high>>1;
                if(c[mid]==x) return mid;
                else if(c[mid]>x) high=mid-1;
                else low=mid+1;
        }
}
bool cmp(node f1, node f2)
{
        return f1.r<f2.r;
}
bool cmp1(node f1, node f2)
{
        return f1.id<f2.id;
}
void PushUp(int rt)
{
        sum[rt]=sum[rt<<1]+sum[rt<<1|1];
}
void Update(int p, int x, int l, int r, int rt)
{
        if(l==r){
                sum[rt]=(LL)x;
                return ;
        }
        int mid=l+r>>1;
        if(p<=mid) Update(p,x,lson);
        else Update(p,x,rson);
        PushUp(rt);
}
LL Query(int ll, int rr, int l, int r, int rt)
{
        if(ll<=l&&rr>=r){
                return sum[rt];
        }
        int mid=l+r>>1;
        LL ans=0;
        if(ll<=mid) ans+=Query(ll,rr,lson);
        if(rr>mid) ans+=Query(ll,rr,rson);
        return ans;
}
int main()
{
        int q, i, T, n, x, j;
        scanf("%d",&T);
        while(T--){
                scanf("%d",&n);
                for(i=0;i<n;i++){
                        scanf("%d",&a[i]);
                        b[i]=a[i];
                }
                sort(b,b+n);
                c[0]=b[0];
                cnt=1;
                for(i=1;i<n;i++){
                        if(b[i]!=b[i-1]){
                                c[cnt++]=b[i];
                        }
                }
                scanf("%d",&q);
                for(i=0;i<q;i++){
                        scanf("%d%d",&qu[i].l,&qu[i].r);
                        qu[i].id=i;
                }
                sort(qu,qu+q,cmp);
                memset(pos,-1,sizeof(pos));
                j=0;
                for(i=0;i<n;i++){
                        x=BS(a[i]);
                        if(pos[x]!=-1){
                                Update(pos[x],0,root);
                        }
                        Update(i,a[i],root);
                        pos[x]=i;
                        while(qu[j].r==i+1){
                                qu[j].ans=Query(qu[j].l-1,qu[j].r-1,root);
                                j++;
                        }
                }
                sort(qu,qu+q,cmp1);
                for(i=0;i<q;i++){
                        printf("%lld\n",qu[i].ans);
                }
        }
        return 0;
}
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值