HDU3333 Turing Tree(线段树)

题目

Source

http://acm.hdu.edu.cn/showproblem.php?pid=3333

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

分析

题目大概说给一个序列,多次询问一个区间内不同数之和。

图灵树的来历原来是这个。。经典的线段树离线所有查询右端点排序的题目吧。。

所有询问右端点排序后,从小到大扫过去,线段树维护序列区间和,用一个map记录各个数最右边出现的位置,一遇到一个数就把之前位置消除并更新当前位置,相当于把各个数尽量向右移动。。

代码

#include<cstdio>
#include<cstring>
#include<map>
#include<algorithm>
using namespace std;
#define MAXN 33333

struct Query{
	int i,l,r;
	bool operator<(const Query &q) const{
		return r<q.r;
	}
}que[111111];

long long tree[MAXN<<2];
int N,x,y;
void update(int i,int j,int k){
	if(i==j){
		tree[k]+=y;
		return;
	}
	int mid=i+j>>1;
	if(x<=mid) update(i,mid,k<<1);
	else update(mid+1,j,k<<1|1);
	tree[k]=tree[k<<1]+tree[k<<1|1];
}
long long query(int i,int j,int k){
	if(x<=i && j<=y) return tree[k];
	int mid=i+j>>1;
	long long ret=0;
	if(x<=mid) ret+=query(i,mid,k<<1);
	if(y>mid) ret+=query(mid+1,j,k<<1|1);
	return ret;
}

int a[MAXN];
long long ans[111111];
int main(){
	int t,n,m;
	scanf("%d",&t);
	while(t--){
		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",&que[i].l,&que[i].r);
			que[i].i=i;
		}
		sort(que,que+m);
		map<int,int> posi;
		memset(tree,0,sizeof(tree));
		for(N=1; N<n; N<<=1);
		int p=0;
		for(int i=0; i<m; ++i){
			while(p<que[i].r){
				++p;
				if(posi.count(a[p])){
					x=posi[a[p]]; y=-a[p];
					update(1,N,1);
				}
				x=p; y=a[p];
				update(1,N,1);
				posi[a[p]]=p;
			}
			x=que[i].l; y=que[i].r;
			ans[que[i].i]=query(1,N,1);
		}
		for(int i=0; i<m; ++i){
			printf("%lld\n",ans[i]);
		}
	}
	return 0;
}
时间: 2024-12-12 07:46:25

HDU3333 Turing Tree(线段树)的相关文章

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 4107 Gangster Segment Tree线段树

这道题也有点新意,就是需要记录最小值段和最大值段,然后成段更新这个段,而不用没点去更新,达到提高速度的目的. 本题过的人很少,因为大部分都超时了,我严格按照线段树的方法去写,一开始居然也超时. 然后修补了两个地方就过了,具体修改的地方请参看程序. 知道最大值段和最小值段,然后修补一下就能过了.不是特别难的题目. #include <stdio.h> #include <string> #include <algorithm> using namespace std; c

ACM学习历程——HDU3333 Turing Tree(线段树 &amp;&amp; 离线操作)

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

CodeForces 620E New Year Tree(线段树的骚操作第二弹)

The New Year holidays are over, but Resha doesn't want to throw away the New Year tree. He invited his best friends Kerim and Gural to help him to redecorate the New Year tree. The New Year tree is an undirected tree with n vertices and root in the v

XTU1238 Segment Tree (线段树&#183;区间最值更新)

对一个数组有四种操作 1: 将区间[ l, r] 中的所有值都加上c 2:将区间 [l, r] 中所有比c大的值改为c 3:将区间 [l, r] 中所有比c小的值改为c 4:输出区间 [l, r] 中所有数的最小值和最大值 对每个操作4输出对应最小值和最大值基础的线段树  在湘潭卡了好久没写出来  线段树维护三个值 区间最大值 maxv, 区间最小值minv, 区间增加的值add  操作1是... http://www.worlduc.com/blog2012.aspx?bid=44692767

HDU - 5390 tree 线段树套字典树 (看题解)

HDU - 5390 看到的第一感觉就是树链剖分 + 线段树套字典树, 感觉复杂度不太对. 其实这种路径其实很特殊, 一个点改变只会影响它儿子到根的路径, 并且这种求最优值问题可以叠加. 所以我们修改的时候对对应dfs序打标记, 询问的时候在线段树上从上往下对每个对应区间求个最优值. 这样还会被卡MLE.. 需要分层优化一下. #pragma GCC optimize(2) #pragma GCC optimize(3) #include<bits/stdc++.h> #define LL l

HDU 3333 Turing Tree(树状数组 || 线段树)

题意:给定一个区间,q个查询,对于每次查询回答这个区间内所有不重复的数的和. 思路:可以考虑使用树状数组来做. 先读入所有查询,离线来做,将所有查询按右端点升序排序. 那么我们从给定区间的第一个元素开始遍历这个区间,在此过程中更新每一个元素上一次出现的位置,每次将现在位置加上a[i]并将lastpos位置减去a[i], 也就是说,我们每一步都是保留与当前位置距离最近的重复元素值,其余置零,那么这样肯定能保证答案正确, 如果遍历到的这个位置恰好是一个询问的右端点,那么我们输出修改后的区间值之和.

hdu-3333 Turing Tree 离线区间+树状数组(区间不同数的和)

题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=3333 题目大意: 给出一数组,以及m个查询区间,每次查询该区间不同数字的和.相同数字只加一次. 解题思路: 离线区间,按照区间右端点进行排序. 这样可以从左到右扫一遍,用尺取法一个一个将数字放入树状数组中. 如果这个数字已经在树状数组里面,记录之前的下标,再从树状数组中删去之前下标的这个数字,在当前下标添加该数字.这样可以保证每一步操作,都会使得树状数组中没有重复元素.这样可以直接用树状数组求不同