「BZOJ3339」Rmq Problem(5366)
题目描述

输入

输出

样例输入
7 5
0 2 1 0 1 3 2
1 3
2 3
1 4
3 6
2 7
提示

这个题说来也挺有意思的
当时集训的时候遇到了一道类似的题,但是题意与此不同,我太菜了,理解成了这个题233结果爆零(蒟蒻咆哮:“唉我AC呢!?”)
所以就把以前写的码翻了出来,交了上去,果然A了2333
当时的写法是这样的:
首先处理出每个数下一次出现的位置,这样每个数字就处理成了 这段区间内这个数没有出现过,数量是O(n)级别的
那么一个询问区间的答案就是所有套在它外面的不出现区间的最小值
具体实现就是首先离线,将“询问区间”和“不出现区间”在一起按照左端点排序,如果相同则优先处理“不出现区间”
此时维护一个线段树,位置表示的是区间的右端点,这个位置上存的是:l小于等于当前扫到的L,且以这个位置为r的区间中数最小的是啥
那么如果扫到了一个提问,那么答案就是(R,N)这个区间内最小值
当时写码的时候有点蒙圈,实际上好像写个单点修改就好了?
#include<cstdio>
#include<cstring>
#include<algorithm>
#define maxn 200005
#define inf n+1
using namespace std;
int a[maxn],nxt[maxn],top;
int n,m,s[maxn*],tag[maxn*];
struct line{
int l,r,x,o;
}q[maxn*];
bool cmp(line A,line B){if(A.l!=B.l)return A.l<B.l;else return A.o<B.o;}
int ans[maxn];
void build(int x,int l,int r){
s[x]=tag[x]=inf;
if(l==r)return;
int mid=(l+r)/;
build(x+x,l,mid);
build(x+x+,mid+,r);
}
void pushdown(int x,int l,int r){
if(l==r){
tag[x]=inf;
return;
}
s[x+x]=min(s[x+x],tag[x]);
tag[x+x]=min(tag[x+x],tag[x]);
s[x+x+]=min(s[x+x+],tag[x]);
tag[x+x+]=min(tag[x+x+],tag[x]);
tag[x]=inf;
return;
}
void add(int x,int l,int r,int L,int R,int k){
if(l==L&&r==R){
s[x]=min(s[x],k);
tag[x]=min(tag[x],k);
return;
}
pushdown(x,l,r);
int mid=(l+r)/;
if(R<=mid)add(x+x,l,mid,L,R,k);
else if(L>mid)add(x+x+,mid+,r,L,R,k);
else add(x+x,l,mid,L,mid,k),add(x+x+,mid+,r,mid+,R,k);
s[x]=min(s[x+x],s[x+x+]);
}
int query(int x,int l,int r,int L,int R){
if(l==L&&r==R)return s[x];
pushdown(x,l,r);
int mid=(l+r)/;
if(R<=mid)return query(x+x,l,mid,L,R);
else if(L>mid)return query(x+x+,mid+,r,L,R);
else return min(query(x+x,l,mid,L,mid),query(x+x+,mid+,r,mid+,R));
}
int main(){
scanf("%d%d",&n,&m);
build(,,n);
nxt[]=n+;
for(int i=;i<=n;i++){
scanf("%d",&a[i]);
nxt[i]=n+;
}
nxt[n+]=n+;
for(int i=n;i>=;i--){
if(nxt[a[i]]-i->){
q[++top].o=;
q[top].l=i+;
q[top].r=nxt[a[i]]-;
q[top].x=a[i];
}
nxt[a[i]]=i;
}
for(int i=;i<=n+;i++)
if(nxt[i]->){
q[++top].o=;
q[top].l=;
q[top].r=nxt[i]-;
q[top].x=i;
}
for(int i=,l,r;i<=m;i++){
scanf("%d%d",&l,&r);
q[++top].o=;
q[top].l=l;
q[top].r=r;
q[top].x=i;
}
sort(q+,q++top,cmp);
for(int i=;i<=top;i++){
if(q[i].o==)
add(,,n,q[i].r,q[i].r,q[i].x);
else{
int A=query(,,n,q[i].r,n);
ans[q[i].x]=A;
}
}
for(int i=;i<=m;i++)printf("%d\n",ans[i]);
return ;
}
不过这个题还有在线的主席树做法
我们维护一个线段树,以数值为位置,里面存的是目前为止这个数最近一次出现的位置
那么询问一个区间l r,就找r之前都加入了的线段树,找里面出现位置小于l且最小的数
这个可以通过在线段树上跳跃实现,具体看代码吧
这是我写(抄)的第一个主席树,感觉还是不太明了的样子。。。இ௰இ
#include<cstdio>
#include<algorithm>
#define maxn 200005
using namespace std;
int n,m,cnt;
int rt[maxn],a[maxn],b[maxn];
struct tree{
int l,r,Min;
}t[*maxn];
int insert(int K,int X,int I,int l,int r){
t[++cnt]=t[K];
K=cnt;
if(l==r){
t[K].l=t[K].r=;
t[K].Min=I;
return cnt;
}
int mid=(l+r)>>;
if(X<=mid)
t[K].l=insert(t[K].l,X,I,l,mid);
else
t[K].r=insert(t[K].r,X,I,mid+,r);
t[K].Min=min(t[t[K].l].Min,t[t[K].r].Min);
return K;
}
int query(int k,int X,int l,int r){
if(l==r)return l;
int mid=(l+r)>>;
if(t[t[k].l].Min<X)
return query(t[k].l,X,l,mid);
else return query(t[k].r,X,mid+,r);
}
int main(){
scanf("%d%d",&n,&m);
rt[]=;
t[]=(tree){,,};
for(int i=;i<=n;i++){
scanf("%d",&a[i]);
if(a[i]<=n)
rt[i]=insert(rt[i-],a[i],i,,n);
else rt[i]=rt[i-];
}
for(int i=,l,r;i<=m;i++){
scanf("%d%d",&l,&r);
printf("%d\n",query(rt[r],l,,n));
}
return ;
}
「BZOJ3339」Rmq Problem(5366)的更多相关文章
- 【bzoj3339】Rmq Problem
[bzoj3339]Rmq Problem Description Input Output Sample Input 7 50 2 1 0 1 3 21 32 31 43 62 7 Sample ...
- BZOJ3339&&3585 Rmq Problem&&mex
BZOJ3339&&3585:Rmq Problem&&mex Description 有一个长度为n的数组{a1,a2,...,an}.m次询问,每次询问一个区间内最 ...
- BZOJ3339:Rmq Problem & BZOJ3585 & 洛谷4137:mex——题解
前者:https://www.lydsy.com/JudgeOnline/problem.php?id=3339 后者: https://www.lydsy.com/JudgeOnline/probl ...
- BZOJ3339 Rmq Problem
[bzoj3339]Rmq Problem Description Input Output Sample Input 7 5 0 2 1 0 1 3 2 1 3 2 3 1 4 3 6 2 7 Sa ...
- 分块+莫队||BZOJ3339||BZOJ3585||Luogu4137||Rmq Problem / mex
题面:P4137 Rmq Problem / mex 题解:先莫队排序一波,然后对权值进行分块,找出第一个没有填满的块,直接for一遍找答案. 除了bzoj3339以外,另外两道题Ai范围都是1e9. ...
- [bzoj3339]Rmq Problem||[bzoj3585]mex_线段树
Rmq Problem bzoj-3339||mex bzoj-3585 题目大意:给定一个长度为n的数列a,多次讯问区间l,r中最小的不属于集合{$A_l,A_{l+1}...A_r$}的非负整数. ...
- 「HAOI2011」Problem c
「HAOI2011」Problem c 传送门 由于这道题本人讲得不好,可以参考这位dalao的博客 我可就直接上代码了... 参考代码: /*---------------------------- ...
- loj#2483. 「CEOI2017」Building Bridges 斜率优化 cdq分治
loj#2483. 「CEOI2017」Building Bridges 链接 https://loj.ac/problem/2483 思路 \[f[i]=f[j]+(h[i]-h[j])^2+(su ...
- loj2353. 「NOI2007」 货币兑换
loj2353. 「NOI2007」 货币兑换 链接 https://loj.ac/problem/2353 思路 题目不重要,重要的是最后一句话 提示 输入文件可能很大,请采用快速的读入方式. 必然 ...
随机推荐
- Tarjan算法求解桥和边双连通分量(附POJ 3352 Road Construction解题报告)
http://blog.csdn.net/geniusluzh/article/details/6619575 在说Tarjan算法解决桥和边双连通分量问题之前我们先来回顾一下Tarjan算法是如何 ...
- 用JAVA的抽象类实现编码组合进度的灵活性
都是实际开发逼出来的吧. 人类真灵活~~~~:) 就是将整个功能的实现在编程时,打散到一个一个文件中,提前写好核心算法, 在TEAM的实现方案确定下来之后,再进行组装. GuessGame.java ...
- C#中的stathread标签【待填的坑】
stathread这种线程是给COM组件使用的线程,如果不适用com对象 如果com对象标记为sta的,则它就是单线程运行的 stathread 组件线程遗留的标签
- ubuntu-kill命令-杀死进程
显示进程pid ps -A 杀进程的命令 kill -s 9 xxx(进程pid)
- innodb_support_xa=1
mysql> show create table t; CREATE TABLE `t` ( `id` ) NOT NULL AUTO_INCREMENT, `num` ) DEFAULT NU ...
- @RequestParam,@PathVariable等注解区别
一.@RequestParam和@PathVariable的区别 1.@RequestParam是从uri中request后面的参数串来取得参数的 2.@PathVariable是从uri模板中取得参 ...
- Java异常的捕获与处理
Java提供了try(尝试).catch(捕捉).finally(最终)这三个关键字来处理异常.在处理各种异常时,需要用到对应的异常类,指的是由程序抛出的对象所属的类. 一.异常处理的使用 由于fin ...
- 轻快的VIM(五):复制
操作相同文本的时候复制尤其有效,在Windows中我们都习惯了先用鼠标选择文本 而Vim下则不用那么麻烦,你甚至可以使用可视模式操作,但这里先略过 我在这一节主要说说命令模式下的复制 在讲复制之前我要 ...
- c#约瑟环实现
约瑟环问题就是有n个人坐成一个圈.从某个人开始报数,数到m的人出列,接着从列出的下一个人开始重新报数,数到m的人再次出列,如此循环,直到所有的人都出列,最后按出列的顺序输出.
- php json 初始化函数(格式化json字符串为php json_decode 标准的字符串)
$json="[{ 'i':100000, 'u':-1,n: '中国'},{i:100001,u:-1,n:'阿尔巴尼亚'},{i:100002,u:-1,n:'阿尔及利亚',}]&quo ...