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 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

喵呜,离散树状数组。

这道题由于相同的值加和的时候只算一次,所以比较伤脑筋==

怎么办呢?

我们发现对于一个值,由于相同的只算一次,所以在任意时间内,这个值只需要出现一次。

如果我们从作往右将原数组更新到树状数组,如果某个值之前出现过,那么我在更新当前的时候,还需要删掉之前那个。

这样就可以保证当前的序列中一个值只出现了一次,而且位置更新成最后出现的位置。

如果只出现一次的话那就又是我们喜闻乐见的那个熟悉的树状数组了呢 喵呜!

但是这样删掉前面出现的元素真心大丈夫? 万一之后又查询了之前你删掉的点岂不是整个人都萌萌哒了?

所以我们可以按照查询区间的又断点排序,保证前面删掉的点以后不会再被查询。

也就是按照顺序,从左往右,边查询,边更新原数组到树状数组。

由于查询区间是无序的,按照右端点排序之后打乱了原来的查询顺序,所以要离线操作。

由于查询区间是无序的,按照右端点排序之后打乱了原来的查询顺序,所以要离线操作。

由于查询区间是无序的,按照右端点排序之后打乱了原来的查询顺序,所以要离线操作。


重要的事情说三遍。

所谓离线操作,就是查询的时候不直接输出答案,而是将答案存起来,然后最后一起输出。

我们需要开一个数组pre [x] 记录x这个数的上一个位置,初始为-1

由 x的范围太大,数组存不下,所以要离散化。

离散化是为了记录一个数上次出现的位置!

注意要开LL 。

/*************************************************************************
    > File Name: code/hdu/3333.cpp
    > Author: 111qqz
    > Email: [email protected]
    > Created Time: 2015年08月07日 星期五 17时04分07秒
 ************************************************************************/

#include<iostream>
#include<iomanip>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<string>
#include<map>
#include<set>
#include<queue>
#include<vector>
#include<stack>
#define y0 abc111qqz
#define y1 hust111qqz
#define yn hez111qqz
#define j1 cute111qqz
#define tm crazy111qqz
#define lr dying111qqz
using namespace std;
#define REP(i, n) for (int i=0;i<int(n);++i)
typedef long long LL;
typedef unsigned long long ULL;
const int inf = 0x7fffffff;
const int N=5E4+3;
LL c[N];
LL n,m,qur;
LL ref[N];
LL pre[N];
LL ori[N];
struct Q
{
    LL val,id;
}q[N];

struct S
{
     LL x,y;
     LL id,ans;
}s[200005];

bool cmp( Q a,Q b)
{
    if (a.val<b.val) return true;
    return false;
}
bool cmp2(S a,S b)
{
    if (a.y<b.y) return true;
    return false;
}

LL lowbit ( int x)
{
    return x&(-x);
}

void update ( LL x,LL delta)
{
    for ( LL i = x ; i <= n ; i = i + lowbit(i))
    {
    c[i] = c[i] + delta;
    }
}
LL sum( LL x)
{
    LL res = 0 ;
    for ( LL i = x; i >= 1 ; i = i - lowbit(i))
    {
    res = res + c[i];
    }
    return res;
}
int main()
{
    int T;
    cin>>T;
    while (T--)
    {
    memset(ref,0,sizeof(ref));
    memset(c,0,sizeof(c));
    memset(pre,-1,sizeof(pre)); //标记上次出现位置的数组
    scanf("%lld",&n);
    for ( LL i = 1 ; i <= n ; i++)
    {
        scanf("%lld",&q[i].val);
        q[i].id  = i;
    }
    sort(q+1,q+n+1,cmp);
    LL cnt  = 0;
    for ( LL i = 1 ; i <= n ; i++ )
    {
        if (q[i].val!=q[i-1].val)
        {
        cnt++;
        }
        ref[q[i].id] = cnt;
        ori[q[i].id] = q[i].val;
    }

    scanf("%lld",&qur);
    for ( LL i = 1 ;i  <= qur; i++ )
    {
        scanf("%lld %lld",&s[i].x,&s[i].y);
        s[i].id = i;
    }
    sort(s+1,s+1+qur,cmp2);
    s[0].y = 0;
    for ( LL i = 1 ; i <= qur  ; i++)
    {
        for ( LL j = s[i-1].y+1 ; j <= s[i].y ; j++)
        {
        int tmp = ref[j];
        if (pre[tmp]==-1)
        {
            update(j,ori[j]);
        }
        else
        {
            update (j,ori[j]);
            update (pre[tmp],-ori[j]);
        }
        pre[tmp] =  j;
        }
        s[s[i].id].ans = sum(s[i].y)-sum(s[i].x-1);
    }
    for ( int i = 1 ; i <= qur ; i++ )
    {
        cout<<s[i].ans<<endl;
    }

    }

    return 0;
}
时间: 2024-10-24 02:42:28

hdu 3333 Turing Tree (树状数组+离线处理+离散化)的相关文章

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

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

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 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

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

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

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 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 树状数组+离线处理

http://acm.hdu.edu.cn/showproblem.php?pid=3333 不错的题,想了很久不知道怎么处理,而且答案没看懂,然后找个例子模拟下别人的代码马上懂了---以后看不懂的话就拿个例子模拟下别人的代码 举个例子:1 3 3 5 3 5 查询 a, 2 4 b, 2 5 最初是这么想的:对于a查询,倘若把第二个数第三个数变成1个3,那么到b查询,又出现了两个3,再做处理似乎还是O(n),而且如果先出现2,5查询,后出现2,4查询,那么还需要把删除的数补回来.....o(╯

Necklace HDU - 3874 (线段树/树状数组 + 离线处理)

Necklace HDU - 3874 Mery has a beautiful necklace. The necklace is made up of N magic balls. Each ball has a beautiful value. The balls with the same beautiful value look the same, so if two or more balls have the same beautiful value, we just count