CodeForces 91B Queue (线段树,区间最值)
http://codeforces.com/problemset/problem/91/B
B. Queue
2 seconds
256 megabytes
standard input
standard output
There are n walruses standing in a queue in an airport. They are numbered starting from the queue's tail: the 1-st walrus stands at the end of the queue and the n-th walrus stands at the beginning of the queue. The i-th walrus has the age equal to ai.
The i-th walrus becomes displeased if there's a younger walrus standing in front of him, that is, if exists such j (i < j), that ai > aj. The displeasure of the i-th walrus is equal to the number of walruses between him and the furthest walrus ahead of him, which is younger than the i-th one. That is, the further that young walrus stands from him, the stronger the displeasure is.
The airport manager asked you to count for each of n walruses in the queue his displeasure.
Input
The first line contains an integer n (2 ≤ n ≤ 105) — the number of walruses in the queue. The second line contains integers ai(1 ≤ ai ≤ 109).
Note that some walruses can have the same age but for the displeasure to emerge the walrus that is closer to the head of the queue needs to be strictly younger than the other one.
Output
Print n numbers: if the i-th walrus is pleased with everything, print "-1" (without the quotes). Otherwise, print the i-th walrus's displeasure: the number of other walruses that stand between him and the furthest from him younger walrus.
Examples
input
output
- -
input
output
- - -
input
output
- - -
题意:
给一个序列,对于第i个数字a[i],在右边找到一个比它小的数,并且最靠右的位置k,输出k-i-1,如果一个都找不到,输出-1。对于序列的每个元素都要输出。
解题思路:
可以用线段树,每个节点表示该段的最小值, 循环一遍数组,每个位置找到最靠右且比它小的数后(已经处理过),将其改为INF,并对线段树进行最小值更新。
查询之前, 先询问整个数组的最小值和当前值的比较,满足最小值小于当前值才有查询的必要,如果满足查询的条件,右边不成立就一定在左边。
上代码:
#include <bits/stdc++.h>
const int INF=0x3f3f3f3f;
typedef long long LL;
const double eps =1e-;
const int mod=1e9+;
const int maxn=1e5+;
using namespace std; struct node
{
int l;
int r;
int val;
}Tr[maxn<<]; int a[maxn]; //存放数据
int ans[maxn]; //存放答案 void PushUp(int u)
{
Tr[u].val=min(Tr[u<<].val,Tr[u<<|].val);
} void Build(int l,int r,int u)
{
Tr[u].l=l; Tr[u].r=r; Tr[u].val=;
if(l==r)
{
Tr[u].val=a[l];
return ;
}
int mid=(l+r)>>;
Build(l,mid,u<<);
Build(mid+,r,u<<|);
PushUp(u);
} void Update(int u,int pos)
{
int l=Tr[u].l; int r=Tr[u].r;
if(l==r)
{
Tr[u].val=INF; //pos位置的答案已得出,将其变为INF
return ;
}
int mid=(l+r)>>;
if(pos<=mid)
Update(u<<,pos);
else
Update(u<<|,pos);
PushUp(u); //向上更新最小值
} void Query(int u,int pos)
{
int l=Tr[u].l; int r=Tr[u].r;
if(l==r)
{
ans[pos]=l-pos-; //得出pos位置的答案
return ;
}
int mid=(l+r)>>;
if(Tr[u<<|].val<a[pos]) //因为是最右边的最小值,先判断右边
Query(u<<|,pos);
else
Query(u<<,pos);
} int main()
{
#ifdef DEBUG
freopen("sample.txt","r",stdin);
#endif int n;
scanf("%d",&n);
for(int i=;i<=n;i++)
scanf("%d",&a[i]);
Build(,n,);
for(int i=;i<=n;i++) //遍历求每一个答案
{
if(Tr[].val>=a[i]) ans[i]=-; //不满足查询条件
else Query(,i);
Update(,i); //更新最小值
}
for(int i=;i<=n;i++)
printf(i==n? "%d\n":"%d ",ans[i]); return ;
}
这题也可以用单调队列,从最后一个数开始处理,若该数比队列中最后一个都小,则是-1,并加入队尾,否则就对队列中的数进行二分(直接粘的题解,学完单调队列再回来填坑)
#include <iostream>
#include <cstdio>
#include <string>
#include <cstring>
#include <cmath>
#include <queue>
#include <vector>
#include <set>
#include <stack>
#include <map>
#include <climits> using namespace std; #define LL long long
const int INF=0x3f3f3f3f;
const int MAXN=; int a[MAXN],ans[MAXN];
int x[MAXN],p[MAXN]; int main()
{
int n;
while(~scanf("%d",&n))
{
for(int i=; i<=n; i++) scanf("%d",&a[i]);
int sum=;
for(int i=n; i>=; i--)
{
if(sum==||x[sum-]>=a[i])
{
x[sum]=a[i];
p[sum++]=i;
ans[i]=-;
}
else
{
int k,l=,r=sum-;
while(l<=r)
{
int mid=(l+r)>>;
if(x[mid]<a[i]) {k=mid;r=mid-;}
else l=mid+;
}
ans[i]=p[k]-i-;
}
}
printf("%d",ans[]);
for(int i=; i<=n; i++)
printf(" %d",ans[i]);
printf("\n");
}
return ;
}
以下题解来自于:https://www.cnblogs.com/sineatos/p/3870790.html
分析题目,我们发现题目需要我们求的值的要求有两个:①最右边的,②比当前考察的值小的。
于是我们需要维护一个这样的序列,这个序列保存着已扫描的值里面的最小值,同时这个序列具有单调性,从开始到当前,序列需要保持递减,对于插入的时候如果无法保持序列的单调性的话,就不要需要插入的值,否则就插入。在求结果的时候,我们可以二分求出比考察点小的,里考察点最远(最右)的那个点,然后求出答案即可。
这里记录一下维护序列单调性的两种方法:①要插入的元素一定会插入,通过抛弃原有的元素来保持单调性。②如果带插入的元素加入会打破单调性的话就不会插入到序列里面。
如果用一个单调队列的维护一个序列,单调队列里面的元素是已经扫描过的元素的最值,次值,次次值······,同时,如果里面是拥有窗口的话,单调队列里面记录的元素可以是元素保存位置的下标,这样就可以更好地维护元素弹出。
对于单调性的研究还需继续。
#include <cstdio>
#include <cstring>
#include <vector>
#include <algorithm>
#define MAX 100002
using namespace std; int a[MAX],ans[MAX];
vector<int> v,num; int main()
{
int n;
//freopen("data.txt","r",stdin);
while(~scanf("%d",&n)){
for(int i=;i<n;i++) scanf("%d",&a[i]);
v.clear();
num.clear();
for(int i=n-;i>=;i--){
if(v.size()== || v.back()>=a[i]){
v.push_back(a[i]); num.push_back(i);
ans[i]=-;
}else{
int j = (lower_bound(v.rbegin(),v.rend(),a[i]) - v.rbegin());
j = (int)v.size() - j - ;
ans[i] = num[j+] - i - ;
}
}
for(int i=;i<n;i++){
if(i) printf(" ");
printf("%d",ans[i]);
}
printf("\n");
}
return ;
} 91B
CodeForces 91B Queue (线段树,区间最值)的更多相关文章
- 【bzoj4695】最假女选手 线段树区间最值操作
题目描述 给定一个长度为 N 序列,编号从 1 到 N .要求支持下面几种操作:1.给一个区间[L,R] 加上一个数x 2.把一个区间[L,R] 里小于x 的数变成x 3.把一个区间[L,R] 里大于 ...
- 【bzoj4355】Play with sequence 线段树区间最值操作
题目描述 维护一个长度为N的序列a,现在有三种操作: 1)给出参数U,V,C,将a[U],a[U+1],...,a[V-1],a[V]都赋值为C. 2)给出参数U,V,C,对于区间[U,V]里的每个数 ...
- 【hdu5306】Gorgeous Sequence 线段树区间最值操作
题目描述 给你一个序列,支持三种操作: $0\ x\ y\ t$ :将 $[x,y]$ 内大于 $t$ 的数变为 $t$ :$1\ x\ y$ :求 $[x,y]$ 内所有数的最大值:$2\ x\ y ...
- HUD.2795 Billboard ( 线段树 区间最值 单点更新 单点查询 建树技巧)
HUD.2795 Billboard ( 线段树 区间最值 单点更新 单点查询 建树技巧) 题意分析 题目大意:一个h*w的公告牌,要在其上贴公告. 输入的是1*wi的w值,这些是公告的尺寸. 贴公告 ...
- cf834D(dp+线段树区间最值,区间更新)
题目链接: http://codeforces.com/contest/834/problem/D 题意: 每个数字代表一种颜色, 一个区间的美丽度为其中颜色的种数, 给出一个有 n 个元素的数组, ...
- HDU-1754I Hate It 线段树区间最值
这道题比较基本,就是用线段树维护区间最值,可以算是模板吧-.. I Hate It Time Limit: 9000/3000 MS (Java/Others) Memory Limit: 32768 ...
- BZOJ-1012[JSOI2008]最大数maxnumber 线段树区间最值
这道题相对简单下面是题目: 1012: [JSOI2008]最大数maxnumber Time Limit: 3 Sec Memory Limit: 162 MB Submit: 6542 Solve ...
- 【POJ】3264 Balanced Lineup ——线段树 区间最值
Balanced Lineup Time Limit: 5000MS Memory Limit: 65536K Total Submissions: 34140 Accepted: 16044 ...
- HDU 4819 Mosaic (二维线段树&区间最值)题解
思路: 二维线段树模板题,马克一下,以后当模板用 代码: #include<cstdio> #include<cmath> #include<cstring> #i ...
随机推荐
- SDN(Software Defined Network):软件定义网络----转载
SDN(Software Defined Network):软件定义网络 传统的网络转发行为: 1)逐设备单独控制,纯分布式控制. 2)控制面和转发面在同一个设备中,耦合紧密. 管理员无法直接操控转发 ...
- CDH6.2安装配置第二篇:CDH安装的前期配置
本篇介绍cdh安装之前需要的一些必要配置,当然这些配置也可以用shell脚本来配置.在安装之前请先配置好yum源,在文中用的统一都是阿里源.在安装的时候,要确保主机的内存是4G以上,要不然会无限重启c ...
- JavaScript 之 原型及原型链
对象[回顾] 通过字面量创建对象 //通过字面量创建对象 var obj1 = { name:'Jack', age: 18 } 通过系统自带的构造函数构造对象 // 通过系统自带的构造函数构造对象 ...
- 零基础程序员入门Linux系统 !如何快速恢复系统?
新手在学习Linux系统的时候,难免会遇到命令输错,或系统出错的难题.那么如何快速解决呢?本文就先给你一个后悔药,让你快速备份并恢复Linux系统.本文将以Ubuntu为例,在这之前,你需要一台服务器 ...
- (转)mysql语句
一.基础 1.说明:创建数据库 CREATE DATABASE database-name 2.说明:删除数据库 drop database dbname 3.说明:备份sql server --- ...
- 查找ARP攻击源
问题: 内网有电脑中了ARP病毒,但是网络拓扑比较复杂.电脑数量较多,排查起来很困难.有什么方法可以找出ARP攻击源?[推荐3]排查方法: 1.使用Sniffer抓包.在网络内任意一台主机上运行抓包软 ...
- windows和ubuntu双系统设置开机默认系统
1.记住grub界面中windows的位置 我的界面如下:windows在第3行 2.选择进入ubuntu系统 3.打开终端,输入如下命令 sudo vim /etc/default/grub 4.看 ...
- 框架-Spring及组件概念
1.什么是Spring Spring框架是一款开源java平台.创建于2003年,轻量级框架(基本版本只有2M). 使用Spring优点: (1) 使用POJOs开发,不再需要EJB容器:如果 ...
- 我的第一次JAVA实训——校园公用房管理系统
老铁们,昨天电脑没电了.这是上周答应的大项目. 别打脸. 详细内容我之后再写,下面是代码地址. Github地址 附:一个寂寞 以上
- mysql数据库大规模数据读写并行时导致的锁表问题
问题介绍 最近在给学校做的一个项目中,有一个功能涉及到考核分数问题. 我当时一想,这个问题并不是很难,于是就直接采用了这样的方法:拿着一个表中的数据作为索引,去挨个遍历相关表中的数据,最后经过算分的过 ...