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

这个题要求区间内不同值的和,一开始没有任何思路,看了题解,原来需要对查询进行离线操作。

因为需要求区间内互异值的和,对于一个固定的区间的话,自然只需要对于相同的值只留一个,其他置零即可。

但是对于动态的查询区间,保留的那个值的位置相对关键。

通过对查询的区间进行排序可以讲区间有序的排列(以区间的右端点递增排序)。

因为这样的话,对于这个数列,从第一个逐个插入,那么区间是[1, 1]->[1, 2]->[1, 3]……这样生成的,如果我们对于a[i],把之前出现过的a[i]都置零,这样此时对于已生成的区间[1, i],我们查询区间和[k, i]的时候(因为区间是按照右端点有序查询的),必然对于任意值p,都是先包含离i最近的那个p,才会包含前面的p,而前面的p已经被置零,故不会加入计算。而离i最近的p又会加入计算,不会影响结果。

所以这样边生成区间[1, i],边对于[k, i]区间查询。对于之前出现过的a[i]置零,便可以达到查询效果。当然最好输出的结果是按照题目要求的查询顺序输出的,这里采用了保存在sum数组中。

不过这里还有一点就是,如何对于之前的a[i]置零,此处采用了map,map里保存了最右端的a[i]的脚标,这样不断更新即可。

代码:

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <set>
#include <map>
#include <queue>
#include <string>
#define LL long long using namespace std; //线段树
//区间每点增值,求区间和
const int maxn = 30005;
struct node
{
int lt, rt;
LL val;
}tree[4*maxn]; //向上更新
void PushUp(int id)
{
tree[id].val = tree[id<<1].val + tree[id<<1|1].val;
} //建立线段树
void Build(int lt, int rt, int id)
{
tree[id].lt = lt;
tree[id].rt = rt;
tree[id].val = 0;//每段的初值,根据题目要求
if (lt == rt)
{
//tree[id].val = 1;
return;
}
int mid = (lt + rt) >> 1;
Build(lt, mid, id<<1);
Build(mid+1, rt, id<<1|1);
//PushUp(id);
} //更改区间内某个点的值
void Change(int lt, int rt, int id, int to)
{
if (lt <= tree[id].lt && rt >= tree[id].rt)
{
tree[id].val = to;
return;
}
int mid = (tree[id].lt + tree[id].rt) >> 1;
if (lt <= mid)
Change(lt, rt, id<<1, to);
if (rt > mid)
Change(lt, rt, id<<1|1, to);
PushUp(id);
} //查询某段区间内的he
LL Query(int lt, int rt, int id)
{
if (lt <= tree[id].lt && rt >= tree[id].rt)
return tree[id].val;
int mid = (tree[id].lt + tree[id].rt) >> 1;
LL ans = 0;
if (lt <= mid)
ans += Query(lt, rt, id<<1);
if (rt > mid)
ans += Query(lt, rt, id<<1|1);
return ans;
} struct qq
{
int from, to;
int id;
}q[100005]; bool cmp(qq a, qq b)
{
return a.to < b.to;
} int a[30005], n, m;
LL sum[100005]; void Work()
{
Build(1, n, 1);
map<int, int> s;
int t, now = 0;
for (int i = 1; i <= n; ++i)
{
t = s[a[i]];
if (t == 0)
{
Change(i, i, 1, a[i]);
s[a[i]] = i;
}
else
{
Change(t, t, 1, 0);
Change(i, i, 1, a[i]);
s[a[i]] = i;
}
for (;now < m && q[now].to == i; now++)
{
sum[q[now].id] = Query(q[now].from, q[now].to, 1);
}
}
} void Output()
{
for (int i = 0; i < m; ++i)
printf("%I64d\n", sum[i]);
} int main()
{
//freopen("test.in", "r", stdin);
int T;
scanf("%d", &T);
for (int times = 0; times < T; ++times)
{
scanf("%d", &n);
for (int i = 1; i <= n; ++i)
scanf("%d", &a[i]);
scanf("%d", &m);
for (int i = 0; i < m; ++i)
{
scanf("%d%d", &q[i].from, &q[i].to);
q[i].id = i;
}
sort(q, q+m, cmp);
Work();
Output();
}
return 0;
}

ACM学习历程——HDU3333 Turing Tree(线段树 && 离线操作)的更多相关文章

  1. ACM学习历程—HDU 5289 Assignment(线段树 || RMQ || 单调队列)

    Problem Description Tom owns a company and he is the boss. There are n staffs which are numbered fro ...

  2. ACM学习历程—HDU 2795 Billboard(线段树)

    Description At the entrance to the university, there is a huge rectangular billboard of size h*w (h ...

  3. ACM学习历程——POJ3321 Apple Tree(搜索,线段树)

          Description There is an apple tree outside of kaka's house. Every autumn, a lot of apples will ...

  4. HDU 3333 Turing Tree 线段树+离线处理

    题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=3333 Turing Tree Time Limit: 6000/3000 MS (Java/Othe ...

  5. ACM学习笔记:可持久化线段树

    title : 可持久化线段树 date : 2021-8-18 tags : 数据结构,ACM 可持久化线段树 可以用来解决线段树存储历史状态的问题. 我们在进行单点修改后,线段树只有logn个(一 ...

  6. HDU 3333 Turing Tree (线段树)

    Turing Tree Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Tota ...

  7. SPOJ D-query && HDU 3333 Turing Tree (线段树 && 区间不相同数个数or和 && 离线处理)

    题意 : 给出一段n个数的序列,接下来给出m个询问,询问的内容SPOJ是(L, R)这个区间内不同的数的个数,HDU是不同数的和 分析 : 一个经典的问题,思路是将所有问询区间存起来,然后按右端点排序 ...

  8. HDU3333 Turing Tree 离线树状数组

    题意:统计一段区间内不同的数的和 分析:排序查询区间,离线树状数组 #include <cstdio> #include <cmath> #include <cstrin ...

  9. HDU3333 Turing Tree(线段树)

    题目 Source http://acm.hdu.edu.cn/showproblem.php?pid=3333 Description After inventing Turing Tree, 3x ...

随机推荐

  1. URL Handle in Swift (二) — 响应链处理 URL

    最后更新: Swift4时候的博客,以前在 CMD markdown 上编辑的,现在搬到这里 在上篇文章-URL Handle in Swift (一) -- URL 分解中,我们已经将URL进行了分 ...

  2. 自己定义ProgressDialog载入图片

    使用系统载入框 mDialog = new ProgressDialog(this); mDialog.setCancelable(true);//能否够被取消 mDialog.setMessage( ...

  3. Oracle更新时间字段

    update field set BEGINDATE=to_date('2015-05-03 10:30:20','yyyy-mm-dd hh24:mi:ss') where NOO='01'  

  4. Objective-C 内存管理之dealloc方法中变量释放处理

    本文转载至 http://blog.sina.com.cn/s/blog_a843a8850101ds8j.html   (一).关于nil http://cocoadevcentral.com/d/ ...

  5. Tensorflow教程

    中文社区 tensorflow笔记:流程,概念和简单代码注释 TensorFlow入门教程集合 tensorboard教程:2017 TensorFlow 开发者峰会 TensorBoard轻松实践  ...

  6. python编程基础:《http://www.cnblogs.com/wiki-royzhang/category/466416.html》

    windows自动化 http://www.cnblogs.com/wiki-royzhang/category/466416.html

  7. CUDA: 共享内存与同步

    CUDA C支持共享内存, 将CUDA C关键字__shared__添加到变量声明中,将使这个变量驻留在共享内存中.对在GPU上启动的每个线程块,CUDA C编译器都将创建该变量的一个副本.线程块中的 ...

  8. GDB调试core文件(3)

    列出一些常见问题: 一,如何使用core文件 使用core文件 在core文件所在目录下键入: gdb -c core 它会启动GNU的调试器,来调试core文件,并且会显示生成此core文件的程序名 ...

  9. SDOI 2017 Day1

    日期:2017-04-10 题解: 第一题: 题目大意:求fi(gcd(i,j))的乘积  i,j属于[1,1e6],数据组数1000组. 类别:套路题. 第二题:BZOJ原题. 题解:LCT套线段树 ...

  10. ES6 Class基本用法

    JavaScript 语言中,生成实例对象的传统方法是通过构造函数.下面是一个例子. function Point(x, y) { this.x = x; this.y = y; } Point.pr ...