SPOJ D-query && HDU 3333 Turing Tree (线段树 && 区间不相同数个数or和 && 离线处理)
题意 : 给出一段n个数的序列,接下来给出m个询问,询问的内容SPOJ是(L, R)这个区间内不同的数的个数,HDU是不同数的和
分析 :
一个经典的问题,思路是将所有问询区间存起来,然后按右端点排序
最后从左到右将原区间扫一遍,扫的过程当中不断将重复出现的数字右移
也就是如果一个数字重复出现,那么我们记录最右边的那个为有效的,其他都视为不存在
这样一旦遇到一个问询区间的右端点就线段树查询即可。
SPOJ:
#include<bits/stdc++.h>
using namespace std;
#define lson l , m , rt << 1
#define rson m + 1 , r , rt << 1 | 1
;
];
void PushUP(int rt) {
sumv[rt] = sumv[rt<<] + sumv[rt<<|];
}
void update(int p,int sc,int l,int r,int rt) {
if (l == r) {
sumv[rt] += sc;
return ;
}
);
if (p <= m) update(p , sc , lson);
else update(p , sc , rson);
PushUP(rt);
}
long long query(int L,int R,int l,int r,int rt) {
if (L <= l && r <= R) {
return sumv[rt];
}
);
;
if (L <= m) ret += query(L , R , lson);
if (R > m) ret += query(L , R , rson);
return ret;
}
struct Interval{
int l, r, id;
bool operator < (const Interval& other) const{
return this->r < other.r;
}
};
Interval sec[];
map<int, int> mp;
int arr[maxn];
int pre[maxn];
long long ans[maxn];
int main(void)
{
, m;
scanf("%d", &n);
; i<=n; i++){
scanf("%d", &arr[i]);
if(!mp.count(arr[i]))
mp[arr[i]] = cnt++;//区间上的每一个数都有一个独特的编号,使用map来进行映射,目的是方便判断此数是否已经重复出现过
}
scanf("%d", &m);
; i<=m; i++){
scanf("%d %d", &sec[i].l, &sec[i].r);
sec[i].id = i;//因为后续有排序操作,而我们又要对问询答案顺序给出,所以记录给出的顺序,方便输出答案
}
sort(sec+, sec++m);//按照右端点排序
bool vis[maxn];
memset(vis, false, sizeof(vis));
, j=; j<=m && i<=n; i++){
int tmp = mp[arr[i]];//拿出这个数的编号
if(vis[tmp]){//如果这个数在前面已经访问过
update(pre[tmp], -, , n, );//将之前的位置信息抹去
update(i, , , n, );//当前的位置才是有效的,所以给当前位置+1
pre[tmp] = i;//更新pre数组方便下次操作
}else{
vis[tmp] = true;
update(i, , , n, );
pre[tmp] = i;
}
while(sec[j].r == i){
ans[sec[j].id] = query(sec[j].l, sec[j].r, , n, );
j++;
}
}
; i<=m; i++){
printf("%I64d\n", ans[i]);
}
;
}
HDU:
#include<bits/stdc++.h>
using namespace std;
#define lson l , m , rt << 1
#define rson m + 1 , r , rt << 1 | 1
;
];
void PushUP(int rt) {
sumv[rt] = sumv[rt<<] + sumv[rt<<|];
}
void update(int p,long long sc,int l,int r,int rt) {
if (l == r) {
sumv[rt] += sc;
return ;
}
);
if (p <= m) update(p , sc , lson);
else update(p , sc , rson);
PushUP(rt);
}
long long query(int L,int R,int l,int r,int rt) {
if (L <= l && r <= R) {
return sumv[rt];
}
);
;
if (L <= m) ret += query(L , R , lson);
if (R > m) ret += query(L , R , rson);
return ret;
}
struct interval{
int L, R, id;
bool operator < (const interval & other) const{
return this->R < other.R;
}
};
interval sec[maxn<<];
bool vis[maxn];
];
int per[maxn];
long long arr[maxn];
map<long long, int> mp;
int main(void)
{
int nCase;
scanf("%d", &nCase);
while(nCase--){
int n;
mp.clear(); ;
memset(sumv, , sizeof(sumv));
scanf("%d", &n);
; i<=n; i++){
scanf("%I64d", &arr[i]);
if(!mp.count(arr[i]))
mp[arr[i]] = cnt++;
}
int m;
scanf("%d", &m);
; i<=m; i++){
scanf("%d %d", &sec[i].L, &sec[i].R);
sec[i].id = i;
}
sort(sec+, sec++m);
memset(vis, false, sizeof(vis));
, j=; j<=m && i<=n; i++){
int num = mp[arr[i]];
if(vis[num]){
update(per[num],-arr[i],,n,);
update(i, arr[i], , n, );
per[num] = i;
}else{
vis[num] = true;
update(i, arr[i], , n, );
per[num] = i;
}
while(i==sec[j].R){
ans[sec[j].id] = query(sec[j].L, sec[j].R, , n, );
j++;
}
}
; i<=m; i++){
printf("%I64d\n", ans[i]);
}
}
}
update in 2018-06-08
学了主席树、以上的离线算法都可以变成在线算法了、戳 主席树
SPOJ D-query && HDU 3333 Turing Tree (线段树 && 区间不相同数个数or和 && 离线处理)的更多相关文章
- HDU 3333 Turing Tree 线段树+离线处理
题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=3333 Turing Tree Time Limit: 6000/3000 MS (Java/Othe ...
- HDU 3333 Turing Tree (线段树)
Turing Tree Time Limit: 6000/3000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Tota ...
- HDU 3333 Turing Tree(树状数组/主席树)
题意 给定一个长度为 \(n\) 的序列,\(m\) 个查询,每次查询区间 \([L,R]\) 范围内不同元素的和. \(1\leq T \leq 10\) \(1 \leq n\leq 300 ...
- HDU 3333 Turing Tree (主席树)
题意:给定上一个序列,然后有一些询问,求区间 l - r 中有多少个不同的数的和. 析:和求区间不同数的方法是一样,只要用主席树维护就好. 代码如下: #pragma comment(linker, ...
- SPOJ GSS1_Can you answer these queries I(线段树区间合并)
SPOJ GSS1_Can you answer these queries I(线段树区间合并) 标签(空格分隔): 线段树区间合并 题目链接 GSS1 - Can you answer these ...
- W同学的新画板 QDUOJ 线段树 区间颜色段数
W同学的新画板 QDUOJ 线段树 区间颜色段数 原题链接 题意 W同学在每天的刻苦学习完成功课之余,都会去找一些有趣的事情来放松自己:恰巧今天他收到了朋友送给他的一套画板,于是他立刻拆开了包装,拿出 ...
- hdu 3333 Turing Tree 图灵树(线段树 + 二分离散)
http://acm.hdu.edu.cn/showproblem.php?pid=3333 Turing Tree Time Limit: 6000/3000 MS (Java/Others) ...
- hdu 3333 Turing Tree(线段树+离散化)
刚看到是3xian大牛的题就让我菊花一紧,觉着这题肯定各种高端大气上档次,结果果然没让我失望. 刚开始我以为是一个普通的线段树区间求和,然后啪啪啪代码敲完测试没通过,才注意到这个求和是要去掉相同的值的 ...
- HDU 6638 - Snowy Smile 线段树区间合并+暴力枚举
HDU 6638 - Snowy Smile 题意 给你\(n\)个点的坐标\((x,\ y)\)和对应的权值\(w\),让你找到一个矩形,使这个矩阵里面点的权值总和最大. 思路 先离散化纵坐标\(y ...
随机推荐
- 【Python开发】【神经网络与深度学习】如何利用Python写简单网络爬虫
平时没事喜欢看看freebuf的文章,今天在看文章的时候,无线网总是时断时续,于是自己心血来潮就动手写了这个网络爬虫,将页面保存下来方便查看 先分析网站内容,红色部分即是网站文章内容div,可以看 ...
- 【机器学习】HK算法(LMSE算法) LMS算法改进保证线性可分时均方误差标准能够找到线性可分的超平面
1.其实HK算法思想很朴实,就是在最小均方误差准则下求得权矢量. 他相对于感知器算法的优点在于,他适用于线性可分和非线性可分得情况,对于线性可分的情况,给出最优权矢量,对于非线性可分得情况,能够判别出 ...
- XSS跨站简析
XSS跨站脚本原理 当应用程序发送给浏览器的页面中包含用户提交的数据,但没有经过适当验证或转义时,就会导致跨站脚本漏洞 这个“跨”实际上属于浏览器的特性,而不是缺陷 (参考:浏览器同源策略) 不去直接 ...
- C语言博课作业11
一.本周作业头 这个作业属与那个课程 C语言程序设计I 这个作业要求在哪里 https://edu.cnblogs.com/campus/zswxy/CST2019-3/homework/10130 ...
- AtCoder Beginner Contest 072
这应该是我第二次打AtCoder, 题目其实并不难,就是自己经验不足想复杂了,再加上自己很笨,愣是做了97分钟才全做出来(最后三分钟,有点小激动..),看着前面大牛半个小时都搞完了,真心膜拜一下,代码 ...
- gym102215题解
A Rooms and Passages 题意 给n个数,从起点出发,一直往右走,遇到一个前面出现过其相反数的正数就停下,问对于每个起点都能走多少步. 分析 倒着递推,如果起点是正数,那么肯定可以走, ...
- sql server 三角函数
正弦函数SIN(x)和反正弦函数ASIN(x) --SIN(x)返回x的正弦,其中x为弧度值 --ASIN(x)返回x的反正弦,即正弦x的值,若x不在-1到1的范围内,则返回NULL 示例:selec ...
- 04.AutoMapper 之投影(Projection)
https://www.jianshu.com/p/031553705417 投影(Projection) 投影将源转换为目标而不是扁平化对象模型.如果没有额为的配置AutoMapper需要一个扁平化 ...
- 085、如何快速部署 Prometheus (2019-05-07 周二)
参考https://www.cnblogs.com/CloudMan6/p/7724576.html 部署环境: 两台 Docker Host 10.12.31.211 10.12.3 ...
- luogu P4382 [九省联考2018]劈配
luogu 我记得我第一次做这道题的时候屁都不会qwq 先考虑第一问,暴力是依次枚举每个人,然后从高到低枚举志愿,枚举导师,能选就选.但是可以发现前面的人选的导师可能会导致后面的人本来可以选到这个志愿 ...