hdu 3333 Turing Tree(树状数组离线操作)

Turing Tree

Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)

Total Submission(s): 3904    Accepted Submission(s): 1325

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

2
3
1 1 4
2
1 2
2 3
5
1 1 2 1 3
3
1 5
2 4
3 5

Sample Output

1
5
6
3
6

Author

[email protected]

Source

HDOJ Monthly Contest – 2010.03.06

Recommend

lcy   |   We have carefully selected several similar problems for you:  1542 1540 1255 1828 3340

题意:求一个区间内不重复数字的和,例如1 1 1 3,区间[1,4]的和为4。

题解:先把要求的区间按右区间升序排序,再把原来的数组按顺序依次插入树状数组,假设当前插入a[i],

先判断a[i]在之前有没有出现过,没有的话直接插入add(i,a[i]),记录这个位置;有的话就当前位置

插入a[i],上一次的位置减去a[i],add(i,a[i]);  add(mp[a[i]],-a[i]);。。然后查询是否有把当前位置作为右

区间的查询Q,有的话就查询该段区间的和。

#include<cstring>
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstdlib>
#include<map>
#include<vector>
#define N 30010
#define M 100010
#define ll long long

using namespace std;

int n,t,q;
int a[N],Rl[N],Rr[N];
map<int,int>mp;///记录上一次出现的位置

struct node {
    int id;
    int l,r;
} Q[M];

ll bit[N],as[M];

bool cmp_1(node a,node b) {
    if(a.r==b.r)return a.l<b.l;
    return a.r<b.r;
}

void add(int i,int v) {
    while(i<=n) {
        bit[i]+=v;
        i+=i&-i;
    }
}

ll getsum(int i) {
    ll s=0;
    while(i>0) {
        s+=bit[i];
        i-=i&-i;
    }
    return s;
}

int main() {
    //freopen("test.in","r",stdin);
    cin>>t;
    while(t--) {
        cin>>n;
        for(int i=1; i<=n; i++)scanf("%d",&a[i]);
        cin>>q;
        for(int i=1; i<=q; i++) {
            scanf("%d%d",&Q[i].l,&Q[i].r);
            Q[i].id=i;
        }
        sort(Q+1,Q+1+q,cmp_1);
        memset(bit,0,sizeof bit);
        memset(Rl,0,sizeof Rl);
        memset(Rr,0,sizeof Rr);
        ///预处理右区间相同的左右区间
        int f=1;
        Rl[Q[f].r]=f;
        Rr[Q[f].r]=f;
        for(int ii=2; ii<=q;) {
            while(Q[f].r==Q[ii].r&&ii<=q)ii++;
            Rl[Q[f].r]=f;
            Rr[Q[f].r]=ii-1;
            f=ii;
        }
        mp.clear();
        for(int i=1; i<=n; i++) {
            ///前面没出现过
            if(!mp[a[i]]) {
                add(i,a[i]);
                mp[a[i]]=i;
            } else {
                ///出现过的话在当前这个位置加上a[i]
                ///在前面出现的位置减去a[i]
                add(i,a[i]);
                add(mp[a[i]],-a[i]);
                mp[a[i]]=i;
            }
            if(!Rl[i])continue;
            int L=Rl[i],R=Rr[i];
            ll ans=getsum(i);
            for(int j=L; j<=R; j++) {
                ll ans_2=ans;
                ans_2-=getsum(Q[j].l-1);
                as[Q[j].id]=ans_2;
            }
        }
        for(int i=1; i<=q; i++) {
            printf("%I64d\n",as[i]);
        }
    }
    return 0;
}

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-10-13 01:06:26

hdu 3333 Turing Tree(树状数组离线操作)的相关文章

HDU 3333 Turing Tree 树状数组 离线查询

题意: 给你一个数列,然后有n个查询,问你给定区间中不同数字的和是多少. 思路还是比较难想的,起码对于蒟蒻我来说. 将区间按照先右端点,后左端点从小到大排序之后,对于每个查询,我只要维护每个数字出现的最后一次就可以了(这个结论稍微想一下就可以证明是正确的). 然后就是简单的点更新,区间求和问题了- #include <cstdio> #include <cstring> #include <iostream> #include <map> #include

hdu 3333 Turing Tree (树状数组+离线处理+离散化)

Turing Tree Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 3981    Accepted Submission(s): 1349 Problem Description After inventing Turing Tree, 3xian always felt boring when solving problems a

HDU 3333 Turing Tree (树状数组)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3333 题意就是询问区间不同数字的和. 比较经典的树状数组应用. 1 //#pragma comment(linker, "/STACK:102400000, 102400000") 2 #include <algorithm> 3 #include <iostream> 4 #include <cstdlib> 5 #include <cstrin

HDU 3333 | Codeforces 703D 树状数组、离散化

HDU 3333:http://blog.csdn.net/julyana_lin/article/details/7877164 这两个题是类似的,都是离线处理查询,对每次查询的区间的右端点进行排序.这里我们需要离散化处理一下,标记一下前面是否出现过这个值,然后不断更新last数组(该数组保存的是每个数最后一次出现的位置).最后用树状数组维护. 1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4

HDU Turing Tree --树状数组+离线处理

题意:统计一段序列[L,R]的和,重复元素只算一次. 解法:容易看出在线做很难处理重复的情况,干脆全部讲查询读进来,然后将查询根据右端点排个序,然后离散化数据以后就可以操作了. 每次读入一个数,如果这个数之前出现过,那么删除之前出现的那个数,改加上这个数,然后进行所有右端点小于等于此时下标的查询即可. 关于正确性,引用sdj222555的话来说,"观察一个区间,我们可以发现,如果出现重复的,尽量删除左边的,保留右边的,那么右端点相同的区间都可以进行查询." 代码: #include &

HDU 3333 Turing Tree(树状数组离线处理)

HDU 3333 Turing Tree 题目链接 题意:给定一个数组,每次询问一个区间,求出这个区间不同数字的和 思路:树状数组离线处理,把询问按右端点判序,然后用一个map记录下每个数字最右出现的位置,因为一个数字在最右边出现,左边那些数字等于没用了,利用树状数组进行单点修改区间查询即可 代码: #include <cstdio> #include <cstring> #include <algorithm> #include <map> using n

HDU 3333 Turing Tree (离散化+离线处理+树状数组)

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 t

hdu 3333 Turing Tree(线段树)

题目链接:hdu 3333 Turing Tree 题目大意:给定一个长度为N的序列,有M次查询,每次查询l,r之间元素的总和,相同元素只算一次. 解题思路:涨姿势了,线段树的一种题型,离线操作,将查询按照右区间排序,每次考虑一个询问,将mv ~ r的点全部标记为存在,并且对于每个位置i,如果A[i]在前面已经出现过了,那么将前面的那个位置减掉A[i],当前位置添加A[i],这样做维护了每个数尽量做,那么碰到查询,用sum[r] - sum[l-1]即可. #include <cstdio>

hdu 4630 树状数组+离线操作+GCD

http://acm.hdu.edu.cn/showproblem.php?pid=4630 重新认识了树状数组. 首先要记住那个树形的图,然后+或-lowbit(i)是自己根据具体问题设定的,不要死于+或者-, 树状数组的特点: 1.+lowbit(i)可以到达包含结点i的上一层父节点    所以用于值的更改 2.-lowbit(i)可以到达不包含i所代表区间的上一层父节点  所以用于值的求和---每个不相交的段加起来 3.C[i]的含义也是根据具体问题去做设定的,但是c[i]覆盖了a[i-2