「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 思路 题目不重要,重要的是最后一句话 提示 输入文件可能很大,请采用快速的读入方式. 必然 ...
随机推荐
- POJ 1703 Find them, Catch them(并查集高级应用)
手动博客搬家:本文发表于20170805 21:25:49, 原地址https://blog.csdn.net/suncongbo/article/details/76735893 URL: http ...
- 【codeforces 793B】Igor and his way to work
[题目链接]:http://codeforces.com/contest/793/problem/B [题意] 给一个n*m大小的方格; 有一些方格可以走,一些不能走; 然后问你从起点到终点,能不能在 ...
- vs--bookmark用法
快捷键 Ctrl+K,K 增加/取消书签 Ctrl+K,P 导航到上一个书签 Ctrl+K,N 导航到下一个标签 Ctrl+K,L 取消所有书签
- percona-xtradb-cluster安装部署
Percona Xtradb Cluster 安装 Percona Xtradb Cluster 介绍 Percona XtraDB Cluster 简称:PXC,是针对MySQL 用户的高可用性和扩 ...
- FZU 1851 组合数
给你两个数n和m,然后让你求组合数C(n,m)中的质因子的个数. 这里用到的一个定理:判断阶乘n!中的质因子 i 的个数的方法---f(n!)=n/i+n/i^2+n/i^3+.....n/i^m ( ...
- android中图型的阴影效果(shadow-effect-with-custom-shapes)
思路: 在自己定义shape中添加一层或多层,并错开.就可以显示阴影效果.为添加立体感,button按下的时候,仅仅设置一层.我们能够通过top, bottom, right 和 left 四个參数来 ...
- C语言——什么是指针?
去年学C语言课时,初步了解了指针的概念,能看懂一些简单的含有指针的程序,但事实上对于指针并没有真正的弄明白它的使用,这点我在半年后的数据结构课程上才深刻的体会到和别人的差距.更加可怕的是,对于当时所得 ...
- use 在php 用法中的总结
1.命名空间 2.匿名函数 3.多继承 4.暂时想到这三个,如果有请补充在评论区
- wampserver配置多站点
1.打开C:\wamp\bin\apache\apache2.2.22\conf\httpd.conf(因安装的路径而异),查找listen 80 下面加上listen 8080 2.然后加上 < ...
- UI常用网站
网站大全 国外的花瓣--Pinterest • The world’s catalog of ideas 字体海洋--求字体网提供中文和英文字体库下载.识别与预览服务,找字体的好帮手 原创设计UI-- ...