Little Elephant and Array 线段树
题目:http://codeforces.com/problemset/problem/220/B
题意
给定一组数据,多次询问区间内某数字出现次数与该数字数值相同的数的个数
思路
一看到区间查询,就会想到线段树,有木有!
单点或区间的修改、查询等可是线段树的强项嘞√
而我们今天的线段树类型为: 离线处理、区间更新、单点查询
给定一个数字序列,线段树每个节点所要记录的状态是 :从此处以及到正在处理的元素处满足题意的ans
上面一句话什么意思嘞
我们做的是 边建树,边查询,当对应状态的线段树建立完成,即可得到答案。
比如 一段序列 : 8 3 4 4 1 3 3 2 2
当我们处理到第7个数的时候,状态分别为 2 2 1 1 1 0 0
以上是线段树的属性介绍,下面就是具体的操作流程
我们需要知道不同数字所出现的所有的位置,用一个二维空间pos存储该信息,比如上面pos[3]存储的数据即为 2、6、7
首先,将所有的询问区间按照右端点进行非递减排序
我们从序列的第一数字开始,建树。
当num数字第 t 次出现时候,如果,t >= num的时候,我们将【1,num第一次出现的位置】的值+1,
如果,t > num 的时候,我们将【1,num第一次出现的位置】的值-1
以此来保证线段树每个节点所要记录的状态
如此做,当处理到第i个数字的时候,查看是否到达当前正在处理的区间的右端点,
如果到达,那么,当前处理区间的左端点的节点状态即为所求
为什么呢,因为我们是一个一个将序列中的元素放入树中的,而我们的询问区间是按照右端点非递减排序的,那么就保证了,处理到第i个序列元素的时候,到达了询问区间右端点,而根据树节点所记录的状态可知,即为答案,而此时的状态,并没有把i处之后的序列元素作考虑,所以,按照区间右端点递增,且序列元素逐一入树,边建树边查询,树节点所记录的状态定为答案。
为了方便,我们将每种数字第一次出现的位置均赋值为0
代码如下:
#include<iostream>
#include<algorithm>
#include<vector>
using namespace std; const int MAXN = ;
int N, M, list[MAXN], s[MAXN], t[MAXN], rank_[MAXN], result[MAXN];
int Tr[MAXN << ], mark[MAXN << ];
vector<int> pos[MAXN]; inline bool cmp(const int a, const int b)
{
return t[a] < t[b];
} void PushDown(int idx); //向下更新 沿para向下更新子树 void Update(int idx, int L, int R, int l, int r, int c); //区间更新 para1:当前结点的树下标 int Query(int idx, int L, int R, int x); //单点询问 int main()
{
cin >> N >> M;
for (int i = ; i <= N; i++)
{
cin >> list[i];
if (list[i] <= N && !pos[list[i]].size())
pos[list[i]].push_back();
}
for (int i = ; i < M; i++)
{
cin >> s[i] >> t[i];
rank_[i] = i;
}
sort(rank_, rank_ + M, cmp);
for (int i = , j = ; i <= N && j < M; i++)
{
if (i == )
int s = ;
if (list[i] <= N)
{
pos[list[i]].push_back(i);
if (pos[list[i]].size() > list[i])
Update(, , N, pos[list[i]][pos[list[i]].size() - list[i] - ] + , pos[list[i]][pos[list[i]].size() - list[i]], );
if (pos[list[i]].size() > list[i] + )
Update(, , N, pos[list[i]][pos[list[i]].size() - list[i] - ] + , pos[list[i]][pos[list[i]].size() - list[i] - ], -);
}
for (; t[rank_[j]] == i && j < M; j++)
result[rank_[j]] = Query(, , N, s[rank_[j]]);
}
for (int i = ; i < M; i++)
printf("%d\n", result[i]);
return ;
} void PushDown(int idx)
{
int left = idx << , right = (idx << ) ^ ;
Tr[left] += mark[idx];
mark[left] += mark[idx];
Tr[right] += mark[idx];
mark[right] += mark[idx];
mark[idx] = ;
} void Update(int idx, int L, int R, int l, int r, int c)
{
if (l <= L && R <= r)
{
Tr[idx] += c;
mark[idx] += c;
return;
}
if (mark[idx])
PushDown(idx);
int mid = (L + R) >> , left = idx << , right = (idx << ) ^ ;
if (l <= mid)
Update(left, L, mid, l, r, c);
if (mid < r)
Update(right, mid + , R, l, r, c);
} int Query(int idx, int L, int R, int x)
{
if (x == L & R == x)
return Tr[idx];
if (mark[idx])
PushDown(idx);
int mid = (L + R) >> , left = idx << , right = (idx << ) ^ ;
if (x <= mid)
return Query(left, L, mid, x);
else
return Query(right, mid + , R, x);
}
当然,作为线段树的好朋友,树状数组当然也可以做喽
见:https://blog.csdn.net/u011026968/article/details/38589907
感谢您的阅读,生活愉快~
Little Elephant and Array 线段树的更多相关文章
- [Codeforces 266E]More Queries to Array...(线段树+二项式定理)
[Codeforces 266E]More Queries to Array...(线段树+二项式定理) 题面 维护一个长度为\(n\)的序列\(a\),\(m\)个操作 区间赋值为\(x\) 查询\ ...
- 【Codeforces718C】Sasha and Array 线段树 + 矩阵乘法
C. Sasha and Array time limit per test:5 seconds memory limit per test:256 megabytes input:standard ...
- codeforces 719E E. Sasha and Array(线段树)
题目链接: E. Sasha and Array time limit per test 5 seconds memory limit per test 256 megabytes input sta ...
- Codeforces 482B Interesting Array(线段树)
题目链接:Codeforces 482B Interesting Array 题目大意:给定一个长度为N的数组,如今有M个限制,每一个限制有l,r,q,表示从a[l]~a[r]取且后的数一定为q,问是 ...
- Codeforces 1114F Please, another Queries on Array? 线段树
Please, another Queries on Array? 利用欧拉函数的计算方法, 用线段树搞一搞就好啦. #include<bits/stdc++.h> #define LL ...
- 2019ccpc网络赛hdu6703 array(线段树)
array 题目传送门 解题思路 操作1是把第pos个位置上的数加上\(10^7\),操作2是找到区间[1,r]中没有且大于k的最小的数.注意到k的范围是小于等于n的,且n的范围是\(10^5\),远 ...
- Codeforces Round #275 Div.1 B Interesting Array --线段树
题意: 构造一个序列,满足m个形如:[l,r,c] 的条件. [l,r,c]表示[l,r]中的元素按位与(&)的和为c. 解法: 线段树维护,sum[rt]表示要满足到现在为止的条件时该子树的 ...
- 暑假集训单切赛第一场 CF 266E More Queries to Array(线段树+二项式展开式)
比赛时,第二题就是做的这个,当时果断没仔细考虑,直接用线段树暴力求.结果易想而知,超时了. 比赛后搜了搜题解,恍然大悟. 思路:显然用线段树,但是由于每次查询都会有变,所以不可能存储题目中的式子. ...
- Codeforces295A - Greg and Array(线段树的成段更新)
题目大意 给定一个序列a[1],a[2]--a[n] 接下来给出m种操作,每种操作是以下形式的: l r d 表示把区间[l,r]内的每一个数都加上一个值d 之后有k个操作,每个操作是以下形式的: x ...
随机推荐
- 关于ES6 Class语法相关总结
关于ES6,其实网上已经有很多的资料可供查询,教程可参考阮一峰大神的ES6入门,本文只是对Class这一语法做一个总结: 一.Class基本语法 constructor方法 constructor是类 ...
- iOS二维码扫描的实现(Swift)
随着二维码的普遍使用,二维码扫描也成为了很多app的一个基本功能,本篇主要来介绍一下如何实现一个简单的二维码扫描功能.本文使用了XCode自带的AVFoundation 库,利用Swfit语言实现. ...
- 【整理】HTML5游戏开发学习笔记(1)- 骰子游戏
<HTML5游戏开发>,该书出版于2011年,似乎有些老,可对于我这样没有开发过游戏的人来说,却比较有吸引力,选择自己感兴趣的方向来学习html5,css3,相信会事半功倍.不过值得注意的 ...
- 51、多线程创建的三种方式之实现Callable接口
实现Callable接口创建线程 Callable接口是在jdk5版本中加入的,这个接口在java.util.concurrent包下面,与其他两种方式不同的地方在于使用Callable接口创建的线程 ...
- JSON数据生成树——(四)
1.页面中准备树的div <div class="user_left_tree_info"> <div class="user_left_tree_in ...
- jq 监听input值的变化
$(".popWeiXing .name").bind("input propertychange", function() { modValue.diyDat ...
- The Art of Memory Forensics-Windows取证(Virut样本取证)
1.前言 The Art of Memory Forensics真是一本很棒的书籍,其中使用volatility对内存进行分析的描述可以辅助我们对更高级类的木马进行分析和取证,这里对书中的命令进行了笔 ...
- Linux下编译安装qemu和libvirt【转】
转自:http://www.cnblogs.com/findumars/p/5679742.html 目录 [hide] 1 安装qemu 1.1 qemu介绍 1.2 下载源文件 1.3 编译安装 ...
- Python基础:内置类型(未完待续)
本文根据Python 3.6.5的官文Built-in Types而写. 目录 1.真值测试 2.布尔操作 -- and, or, not 3.比较 4.数字型 -- int, float, comp ...
- java基础21 System类和Runtime类
一.System系统类 1.1.System系统类 主要用于获取系统信息 1.2.System类的常用方法 arraycopy(Object src, int srcPos, Object dest, ...