题目: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 线段树的更多相关文章

  1. [Codeforces 266E]More Queries to Array...(线段树+二项式定理)

    [Codeforces 266E]More Queries to Array...(线段树+二项式定理) 题面 维护一个长度为\(n\)的序列\(a\),\(m\)个操作 区间赋值为\(x\) 查询\ ...

  2. 【Codeforces718C】Sasha and Array 线段树 + 矩阵乘法

    C. Sasha and Array time limit per test:5 seconds memory limit per test:256 megabytes input:standard ...

  3. codeforces 719E E. Sasha and Array(线段树)

    题目链接: E. Sasha and Array time limit per test 5 seconds memory limit per test 256 megabytes input sta ...

  4. Codeforces 482B Interesting Array(线段树)

    题目链接:Codeforces 482B Interesting Array 题目大意:给定一个长度为N的数组,如今有M个限制,每一个限制有l,r,q,表示从a[l]~a[r]取且后的数一定为q,问是 ...

  5. Codeforces 1114F Please, another Queries on Array? 线段树

    Please, another Queries on Array? 利用欧拉函数的计算方法, 用线段树搞一搞就好啦. #include<bits/stdc++.h> #define LL ...

  6. 2019ccpc网络赛hdu6703 array(线段树)

    array 题目传送门 解题思路 操作1是把第pos个位置上的数加上\(10^7\),操作2是找到区间[1,r]中没有且大于k的最小的数.注意到k的范围是小于等于n的,且n的范围是\(10^5\),远 ...

  7. Codeforces Round #275 Div.1 B Interesting Array --线段树

    题意: 构造一个序列,满足m个形如:[l,r,c] 的条件. [l,r,c]表示[l,r]中的元素按位与(&)的和为c. 解法: 线段树维护,sum[rt]表示要满足到现在为止的条件时该子树的 ...

  8. 暑假集训单切赛第一场 CF 266E More Queries to Array(线段树+二项式展开式)

    比赛时,第二题就是做的这个,当时果断没仔细考虑,直接用线段树暴力求.结果易想而知,超时了. 比赛后搜了搜题解,恍然大悟. 思路:显然用线段树,但是由于每次查询都会有变,所以不可能存储题目中的式子.   ...

  9. Codeforces295A - Greg and Array(线段树的成段更新)

    题目大意 给定一个序列a[1],a[2]--a[n] 接下来给出m种操作,每种操作是以下形式的: l r d 表示把区间[l,r]内的每一个数都加上一个值d 之后有k个操作,每个操作是以下形式的: x ...

随机推荐

  1. 逆序对 inversion

      评测传送门 [问题描述] 有一个1 − n的排列,你会依次进行m次操作,第i次操作表示为(x i , y i ),交换以这两个 值为下标的元素,每次操作有一半的概率成功,你需要求出最后序列的逆序对 ...

  2. equals方法变量和常量位置区别

    对于字符串比较,我的习惯用法是   变量.equals(常量) 比如:     a.equals("a") 今天看视频才知道变量在前面与后面有很大影响,正确的写法是常量放前面(可以 ...

  3. Hibernate5笔记9--Hibernate注解式开发

    Hibernate注解式开发: (1)注解式开发的注意点: Hibernate中使用注解,主要是为了替代映射文件,完成“类到表,属性到字段”的映射.  JPA提供了一套功能强大的注解.Hibernat ...

  4. pytorch--cnn的理解

    class Model(nn.Module): def __init__(self): super(Model, self).__init__() self.conv1 = nn.Conv2d(1, ...

  5. React-Native 之 环境配置和简单使用

    # 前言 学习本系列内容需要具备一定 HTML 开发基础,没有基础的朋友可以先转至 HTML快速入门(一) 学习 本人接触 React Native 时间并不是特别长,所以对其中的内容和性质了解可能会 ...

  6. 转载: Android开源库V - Layout:淘宝、天猫都在用的UI框架,赶紧用起来吧!

    阿里的UI库... 分析的很精辟... http://blog.csdn.net/carson_ho/article/details/71077193

  7. 洛谷P2279消防局的设立

    传送门啦 一个很摸不清头脑的树形dp 状态: $ dp[i][0] $ :选自己 $ dp[i][1] $ :选了至少一个儿子 $ dp[i][2] $ :选了至少一个孙子 ------------- ...

  8. WinScp几个极大提高开发效率的小功能

    WinSCP 是一个 Windows 环境下使用 SSH 的开源图形化 SFTP 客户端.同时支持 SCP 协议.它的主要功能就是在本地与远程计算机间安全的复制文件. 最近研究了一下winscp的一些 ...

  9. Qt通过ODBC来操作Excel

    示例代码: #include<QtCore/QCoreApplication> #include<QtSql> #include<QObject> #include ...

  10. c 语言文本文件判断是否到达结尾的问题

    在c语言中,判断文件结尾有两种方法,第一种是使用feof()函数,feof(fp)用于测试fp所指向的文件的当前状态是否为“文件结束”.如果是,函数则返回的是非0值(真),否则为0(假),要注意的是, ...