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 ...
随机推荐
- 好的MongoDB学习文章链接
1.MongoDB 极简实践入门 2.MongoDB中文社区 3.极客学院Mongodb 教程
- 奇葩字符 "a๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎" 的简单分析
这个其实之前火过一阵子,当时也没怎么注意,今天看到空间里又有人在刷这个字符了,所以决定分析下他是什么东西.复制这个字符在控制台查看 "a๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎๎".l ...
- Collections -- 集合的工具类
Collections是JDK针对集合提供的一个工具类,他提供一系列静态方法实现对各种集合的搜索.排序.线程安全化等操作. 1.搜索 如可以使用Collections提供的二分查找方法binarySe ...
- C# XML序列化和反序列化
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.I ...
- c++ STL 常用容器元素类型相关限制 指针 引用
c++ 的 STL 中主要有 vector , list, map, set , multimap,multiset 这些容器完全支持使用内置类型和指针(指针注意内存泄露问题). 就是说乱用智能指针 ...
- JavaScript入门--慕课网学习笔记
JAVASCRIPT—(慕课网)入门篇 我们来看看如何写入JS代码?你只需一步操作,使用<script>标签在HTML网页中插入JavaScript代码.注意, <script&g ...
- zookeeper zkClient api 使用
操作步骤: 一.引入zkclient的jar包(maven方式) <dependency> <groupId>com.101tec</groupId> <ar ...
- Apple Notification Center Service--ANCS【转】
Apple Notification Center Service 转自:http://studentdeng.github.io/blog/2014/03/22/ancs/ MAR 22ND, 20 ...
- 串口流控制详解(CTS/RTS,DTR/DSR)
1 首先看下关于流控相关的几个端口的解释如下图 除了必要的地(GND)要连接外,其它连如下 步骤阅读 2 计算机和猫(MODEM)的连接 步骤阅读 步骤阅读 3 计算机和非猫的连接(null mod ...
- lombok java代码助手
是不一个不错的代码生成工具,可以实现将代码更精简,且不失代码效率的一种不错的方法 https://www.cnblogs.com/qnight/p/8997493.html 通过java bean v ...