题目: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. 嵌入式Linux系统挂载NFS系统

    在建立交叉编译环境的时候,经常需要网嵌入式Linux环境中拷贝文件,nfs网络共享文件系统是一种很方便的方式. 在嵌入式Linux挂载nfs系统,需要用到如下命令: mount -t nfs -o n ...

  2. HDU 1017 A Mathematical Curiosity 数学题

    解题报告:输入两个数,n和m,求两个数a和b满足0<a<b<n,并且(a^2+b^2+m) % (a*b) =0,这样的a和b一共有多少对.注意这里的b<n,并不可以等于n. ...

  3. python+selenium初学者常见问题处理

    要做web自动化,第一件事情就是搭建自动化测试环境,那就没法避免的要用到selenium了. 那在搭建环境和使用过程中经常会遇到以下几类问题: 1.引入selenium包失败: 出现这种错误,一般分为 ...

  4. 【codeforces】【比赛题解】#960 CF Round #474 (Div. 1 + Div. 2, combined)

    终于打了一场CF,不知道为什么我会去打00:05的CF比赛…… 不管怎么样,这次打的很好!拿到了Div. 2选手中的第一名,成功上紫! 以后还要再接再厉! [A]Check the string 题意 ...

  5. 冲量:momentum

    参见:http://www.jianshu.com/p/58b3fe300ecb,这个博客里有冲量的python实现的代码和讲解 “冲量”这个概念源自于物理中的力学,表示力对时间的积累效应. 在普通的 ...

  6. go 指针类型

    变量和内存地址 每个变量都有内存地址,可以说通过变量来操作对应大小的内存 var a int32 a = fmt.Printf(“%d\n”, a) fmt.Printf(“%p\n”, &a ...

  7. linux下使用indent整理代码(代码格式化)【转】

    转自:https://blog.csdn.net/jiangjingui2011/article/details/7197069 常用的设置: indent -npro -kr -i8 -ts8 -s ...

  8. java基础20 StringBuffer缓冲类

    1.概要 StringBuffer 其实就是一个存储字符的容器 字符串特点:字符串是常量;它们创建之后不能更改了字符串一旦发生变化,那么立马创建一个新的对象.注意:字符串的内容不适合频繁修改的,因为一 ...

  9. git —— Feature分支

    添加新功能时,新建feature分支 分支上开发完成后,再进行合并.最后删除feature分支 $ git checkout -b feature-vulcan 开发完毕后,切换回添加的分支,进行合并 ...

  10. 关于json中转义字符/正斜杠的问题。

    1.首先有关转义字符 可以看百度百科: 先不管/是否需要转义,我们去json的官方网站去看看:http://www.json.org/ 可见有这个,那么意思是 json中 又规定建议了一下,意思是虽然 ...