Hdu-3333 Turning Tree (离线树状数组/线段树)
题目大意:先给出n个数字。面对q个询问区间,输出这个区间不同数的和。
题解:这道题有多重解法。我另一篇博客写了分块的解法 HDU-3333 Turing Tree 分块求区间不同数和 。
这里讲一下离线树状数组或者线段树的解法。
先讲一下我们在线(按询问顺序)做这道题会有什么麻烦。因为一个区间重复的数我们只算一个,那么我们认为对于一个区间,重复的数我们只算最接近区间右段点的哪一个。但是因为按询问顺序,它的右端点是会起伏的。所以我们不好统计到底对于每一个询问区间,哪一个才是该区间重复数中有效的哪一个。
那么我们转变一下思路。改成离线算法。先把询问区间按右端点排序。那么因为区间右段点的单调性,按照这个顺序我们可以只算重复数的最右边的那个。
具体做法是排序询问右端点r,把1-r的数都加入到树状数组。如果该数在前面有重复数last[i]。那么就把last[i]的值在树状数组去掉,把r点的值在树状数组上加上。那么保证在1-r内每个数只会出现一次。
AC代码如下:
#include<iostream>
#include<cstdio>
#include<map>
#include<algorithm>
using namespace std;
const int N=+;
const int M=+;
struct node{
int x,y,num;
bool operator < (const node& t) {
return y<t.y;
}
}q[M];
int n,m,a[N];
long long sum[*N],ans[M],last[N];
map<int,int> lst; int lowbit(int x) { return x&(-x); } void update(int x,int v) {
while (x<=n) {
sum[x]+=v;
x+=lowbit(x);
}
} long long query(int x) {
long long ans=;
while (x) {
ans+=sum[x];
x-=lowbit(x);
}
return ans;
} int main()
{
int T;
scanf("%d",&T);
while (T--) {
scanf("%d",&n);
for (int i=;i<=n;i++) scanf("%d",&a[i]);
lst.clear();
for (int i=;i<=n;i++) last[i]=;
for (int i=;i<=n;i++) {
last[i]=lst[a[i]];
lst[a[i]]=i;
} scanf("%d",&m);
for (int i=;i<=m;i++) {
scanf("%d%d",&q[i].x,&q[i].y);
q[i].num=i;
} sort(q+,q+m+);
int now=;
for (int i=;i<=n;i++) sum[i]=;
for (int i=;i<=m;i++) {
while (now<q[i].y) {
now++;
update(now,a[now]);
if (last[now]) update(last[now],-a[now]);
}
ans[q[i].num]=query(q[i].y)-query(q[i].x-);
}
for (int i=;i<=m;i++) printf("%lld\n",ans[i]);
}
return ;
}
Hdu-3333 Turning Tree (离线树状数组/线段树)的更多相关文章
- 树状数组 && 线段树应用 -- 求逆序数
参考:算法学习(二)——树状数组求逆序数 .线段树或树状数组求逆序数(附例题) 应用树状数组 || 线段树求逆序数是一种很巧妙的技巧,这个技巧的关键在于如何把原来单纯的求区间和操作转换为 求小于等于a ...
- hdu1394(枚举/树状数组/线段树单点更新&区间求和)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1394 题意:给出一个循环数组,求其逆序对最少为多少: 思路:对于逆序对: 交换两个相邻数,逆序数 +1 ...
- 洛谷P2414 阿狸的打字机 [NOI2011] AC自动机+树状数组/线段树
正解:AC自动机+树状数组/线段树 解题报告: 传送门! 这道题,首先想到暴力思路还是不难的,首先看到y有那么多个,菜鸡如我还不怎么会可持久化之类的,那就直接排个序什么的然后按顺序做就好,这样听说有7 ...
- hdu 1166:敌兵布阵(树状数组 / 线段树,入门练习题)
敌兵布阵 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Total Submis ...
- hdu 5147 Sequence II【树状数组/线段树】
Sequence IITime Limit: 5000/2500 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Problem ...
- hdu 3966 Aragorn's Story(树链剖分+树状数组/线段树)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3966 题意: 给出一棵树,并给定各个点权的值,然后有3种操作: I C1 C2 K: 把C1与C2的路 ...
- BZOJ 3333 排队计划 树状数组+线段树
题目大意:给定一个序列.每次选择一个位置,把这个位置之后全部小于等于这个数的数抽出来,排序,再插回去,求每次操作后的逆序对数 首先我们每一次操作 对于这个位置前面的数 因为排序的数与前面的数位置关系不 ...
- hdu 1166 敌兵布阵——(区间和)树状数组/线段树
pid=1166">here:http://acm.hdu.edu.cn/showproblem.php?pid=1166 Input 第一行一个整数T.表示有T组数据. 每组数据第一 ...
- HDU 1166 敌兵布阵 树状数组||线段树
http://acm.hdu.edu.cn/showproblem.php?pid=1166 题目大意: 给定n个数的区间N<=50000,还有Q个询问(Q<=40000)求区间和. 每个 ...
随机推荐
- Flutter-AppBar
1.1 简介 AppBar “应用栏” 应用栏由工具栏组成,或者是工具栏和其他 widget 组合形成,例如 TabBar和FlexibleSpaceBar; 应用栏通常用于 Scaffold.app ...
- Flutter pubspec.yaml配置文件
name: flutter_app1 # 应用名称 description: A new Flutter application. # 应用描述 # The following defines the ...
- 使用字符流(Writer、Reader)完成对文件的读写操作
字符流 字符输出流:Writer,对文件的操作使用子类FileWriter 字符输入流:Reader,对文件的操作使用子类FileReader 每次操作的是一个字符 文件字符操作流会自带缓存,默认大小 ...
- 正则表达式中的Quantifiers
?: Match an element zero or one time 例如: colou?r: color 或 colour 但不能是 colo2r *: Match an element zer ...
- JavaWeb(三):JSP
JSP是JavaServer Page的缩写,也就是服务端网页. 一.概述 1.1 为什么使用JSP 在很多动态网页中,绝大部分内容都是固定不变的,只有局部内容需要动态产生和改变.JSP是简化Serv ...
- boost serialization
Archive An archive is a sequence of bytes that represented serialized C++ objects. Objects can be ad ...
- 【Mybatis】Mybatis缓存
mybatis提供了缓存机制减轻数据库压力,提高数据库性能 mybatis的缓存分为两级:一级缓存.二级缓存 一级缓存是SqlSession级别的缓存,缓存的数据只在SqlSession内有效 二级缓 ...
- jmeter+ant+jenkins搭建接口自动化测试环境
jmeter+ant+jenkins搭建接口自动化测试环境(基于win) 1.jmeter jmeter依赖java运行环境,所以需要提前下载jdk并配置好环境变量 官网下载(http://jmete ...
- myeclipse svn重新定位 本地文件 svn 重新定位
我们在用工具myeclipse开发项目时,当资源库存储空间不够时,我们就需要添加资源库,涉及到我们切换项目资源库,下面就介绍一下svn资源库重新定位步骤 1,window到show view到othe ...
- 【HDOJ6583】Typewriter(SAM,DP)
题意:给定一个由小写字母组成的字符串,每次可以花费p在串后加上任意一个字母,花费q在串后复制一个当前串的子串,问生成字符串的最小花费 n<=2e5,1<=p,q<2^31 思路: S ...