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 ...
随机推荐
- iOS二维码扫描的实现(Swift)
随着二维码的普遍使用,二维码扫描也成为了很多app的一个基本功能,本篇主要来介绍一下如何实现一个简单的二维码扫描功能.本文使用了XCode自带的AVFoundation 库,利用Swfit语言实现. ...
- 【转】C#中Graphics的画图代码
C#中Graphics的画图代码[转] 架上图片了你就可以在画板上涂改了啊 我要写多几个字上去string str = "Baidu"; //写什么字?Font font = Fo ...
- 基本控件文档-UISwitch属性
CHENYILONG Blog 基本控件文档-UISwitch属性 Fullscreen UISwitch属性 技术博客http://www.cnblogs.com/ChenYilong/ 新 ...
- 【leetcode 简单】 第六十一题 存在重复元素
给定一个整数数组,判断是否存在重复元素. 如果任何值在数组中出现至少两次,函数返回 true.如果数组中每个元素都不相同,则返回 false. 示例 1: 输入: [1,2,3,1] 输出: true ...
- mybatis的配置文件中<selectKey>标签问题
1.mybatis的配置文件中,使用sequence生成主键 未执行add方法之前,主键未生成(null):刚执行add之后,主键即生成(212) 这里的重点是,一旦执行add方法,配置文件中的sel ...
- Cesium entity click
var url = 'http://202.107.245.51:81/user/dev/api/v2/sql?rows_per_page=40&page=0&sort_order=a ...
- MySQL增量备份与恢复实例【转】
小量的数据库可以每天进行完整备份,因为这也用不了多少时间,但当数据库很大时,就不太可能每天进行一次完整备份了,这时候就可以使用增量备份.增量备份的原理就是使用了mysql的binlog日志.本次操作的 ...
- 全面了解Nginx主要应用场景【转】
前言 本文只针对 Nginx 在不加载第三方模块的情况能处理哪些事情,由于第三方模块太多所以也介绍不完,当然本文本身也可能介绍的不完整,毕竟只是我个人使用过和了解到过得.所以还请见谅,同时欢迎留言交流 ...
- Scrapy的【SitemapSpider】的【官网示例】没有name属性
Windows 10家庭中文版,Python 3.6.4,Scrapy 1.5.0, 上午看了Scrapy的Spiders官文,并按照其中的SitemapSpider的示例练习,发现官文的示例存在问题 ...
- Flask:abort()函数
Windows 10家庭中文版,Python 3.6.4,Flask 1.0.2 abort()函数用于提前退出(Google翻译abort)一个请求,并用指定的错误码返回. 函数原型如下: flas ...