HDU - 3333 - Turing Tree(线段树+离线)

14 篇文章 0 订阅
2 篇文章 0 订阅

Turing Tree

Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 5672    Accepted Submission(s): 2025


Problem Description
After inventing Turing Tree, 3xian always felt boring when solving problems about intervals, because Turing Tree could easily have the solution. As well, wily 3xian made lots of new problems about intervals. So, today, this sick thing happens again...

Now given a sequence of N numbers A1, A2, ..., AN and a number of Queries(i, j) (1≤i≤j≤N). For each Query(i, j), you are to caculate the sum of distinct values in the subsequence Ai, Ai+1, ..., Aj.
 

Input
The first line is an integer T (1 ≤ T ≤ 10), indecating the number of testcases below.
For each case, the input format will be like this:
* Line 1: N (1 ≤ N ≤ 30,000).
* Line 2: N integers A1, A2, ..., AN (0 ≤ Ai ≤ 1,000,000,000).
* Line 3: Q (1 ≤ Q ≤ 100,000), the number of Queries.
* Next Q lines: each line contains 2 integers i, j representing a Query (1 ≤ i ≤ j ≤ N).
 

Output
For each Query, print the sum of distinct values of the specified subsequence in one line.
 

Sample Input
 
 
231 1 421 22 351 1 2 1 331 52 43 5
 

Sample Output
 
 
15636
 

Author
3xian@GDUT
 

Source
 

题意:
求区间 [ i , j ] 内所有不同的数的和。
求单独一个区间的值,可以这样考虑:因为区间内所有相同的数只算一次,所以可以把最前面的该数,或最后的有效。其它的该数无效就是看作0,然后就求区间和。
假设每种数都是最后一个有效,当求出区间 [ 1 , R ] 的值后,可以利用更新后的数组直接求和得到 [L , R - k]  k>=0
求[L , R + k] 则需要继续更新数组,将前面出现的变0,新出现的变1


#include <iostream>
#include <string.h>
#include <stdio.h>
#include <algorithm>
#include <map>
using namespace std;
#define LL long long
#define lx x<<1
#define rx x<<1|1
const int N = 3e4 + 10;
int T,n,q;
map<LL,int>mp;
LL a[N],sum[N<<2];
struct node{
    int l,r,id;
    LL ans;
}p[N*10];
bool cmp1(node a,node b){return a.r<b.r;}
bool cmp2(node a,node b){return a.id<b.id;}
void add(int x,LL val,int pos,int L,int R){
    if(L==R){
        sum[x] += val;
        return;
    }
    int mid = (L+R)>>1;
    if(pos<=mid) add(lx, val, pos, L, mid);
    else add(rx, val, pos, mid+1, R);
    sum[x] = sum[lx] + sum[rx];
}
LL Sum(int x,int l,int r,int L,int R){
    if(l<=L&&R<=r) return sum[x];
    LL ans = 0; int mid = (L+R)>>1;
    if(mid>=l) ans += Sum(lx, l, r, L, mid);
    if(mid<r) ans += Sum(rx, l, r, mid+1, R);
    return ans;
}
int main()
{
    scanf("%d",&T);
    while(T--){
        memset(sum,0,sizeof sum);
        mp.clear();
        scanf("%d",&n);
        for(int i=1;i<=n;i++) scanf("%lld",&a[i]);
        scanf("%d",&q);
        for(int i=0;i<q;i++){
            scanf("%d%d",&p[i].l,&p[i].r);
            p[i].id = i;
        }
        sort(p,p+q,cmp1);
        for(int i=p[0].r;i>=1;i--){ //要从第一个数开始,因为后面的区间的L可能小于该区间的L
            if(mp[a[i]]) continue; //后面会出现
            add(1, a[i], i, 1, n);
            mp[a[i]] = i;
        }
        p[0].ans = Sum(1, p[0].l, p[0].r, 1, n);
        for(int i=1;i<q;i++){
            for(int j=p[i].r;j>p[i-1].r;j--){
                int pos = mp[a[j]];
                if(pos>j) continue;//后面会出现
                if(pos<j&&pos) add(1, -a[j], pos, 1, n);//前面出现过,现在又出现了
                mp[a[j]] = j;
                add(1, a[j], j, 1, n);
            }
            p[i].ans = Sum(1, p[i].l, p[i].r, 1, n);
        }
        sort(p,p+q,cmp2);
        for(int i=0;i<q;i++) printf("%lld\n",p[i].ans);
    }
    return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值