题目描述

题目传送门

分析

考虑对于 \([l,r]\),如何求出包住它的长度最短的好区间

做法就是用一个指针从 \(r\) 向右扫,每次查询以当前指针为右端点的最短的能包住 \([l,r]\) 的好区间

第一个查询到的就是想要的区间

一定不会存在一个与这个区间交叉的区间更优的情况

因为这种情况两个区间交叉的部分一定会在之前被查询到

这样的话就可以把所有的询问离线下来,按照右端点从小到大排序依次处理

只需要快速地查询长度最短的好区间即可

这可以用线段树去维护

我们把线段树的节点定义为以某个点为左端点,以扫到的点为右端点的区间中连续区间的个数

线段树要维护的信息就是连续区间个数的最小值以及区间加和操作中的 \(lazy\) 标记

每次从右边新加入一个点 \(i\) 时,我们把区间 \([1,i]\) 整体加 \(1\)

代表此时又多了一个不连续的区间

此时我们去找 \(a[i]+1\) 和 \(a[i]-1\) 的位置,如果它们的位置在 \(i\) 的左边,我们就把 \([1,wz[a[i]-1]]\) 或者 \([1,wz[a[i]+1]]\) 整体减一,代表包含 \(a[i]+1\) 或者 \(a[i]-1\) 的区间可以与 \(a[i]\) 合并形成一个大区间

如果一个区间是合法的,那么连续区间个数就是一,线段树上记录的最小值就是一

在线段树上二分查找即可

代码

#include<cstdio>
#include<algorithm>
#include<cmath>
#include<set>
#define rg register
inline int read(){
rg int x=0,fh=1;
rg char ch=getchar();
while(ch<'0' || ch>'9'){
if(ch=='-') fh=-1;
ch=getchar();
}
while(ch>='0' && ch<='9'){
x=(x<<1)+(x<<3)+(ch^48);
ch=getchar();
}
return x*fh;
}
const int maxn=1e5+5;
struct trr{
int l,r,mmin,laz;
}tr[maxn<<2];
void push_up(rg int da){
tr[da].mmin=std::min(tr[da<<1].mmin,tr[da<<1|1].mmin);
}
void push_down(rg int da){
if(tr[da].laz){
tr[da<<1].laz+=tr[da].laz;
tr[da<<1|1].laz+=tr[da].laz;
tr[da<<1].mmin+=tr[da].laz;
tr[da<<1|1].mmin+=tr[da].laz;
tr[da].laz=0;
}
}
void build(rg int da,rg int l,rg int r){
tr[da].l=l,tr[da].r=r;
if(l==r) return;
rg int mids=(l+r)>>1;
build(da<<1,l,mids),build(da<<1|1,mids+1,r);
}
void xg(rg int da,rg int l,rg int r,rg int val){
if(tr[da].l>=l && tr[da].r<=r){
tr[da].laz+=val,tr[da].mmin+=val;
return;
}
push_down(da);
rg int mids=(tr[da].l+tr[da].r)>>1;
if(l<=mids) xg(da<<1,l,r,val);
if(r>mids) xg(da<<1|1,l,r,val);
push_up(da);
}
int cx(rg int da,rg int l,rg int r){
if(tr[da].l!=tr[da].r) push_down(da);
if(tr[da].l>=l && tr[da].r<=r){
if(tr[da].mmin==1){
if(tr[da].l==tr[da].r) return tr[da].l;
else if(tr[da<<1|1].mmin==1) return cx(da<<1|1,l,r);
else return cx(da<<1,l,r);
} else {
return -1;
}
}
rg int mids=(tr[da].l+tr[da].r)>>1,tmp1=-1,tmp2=-1;
if(l<=mids) tmp1=cx(da<<1,l,r);
if(r>mids) tmp2=cx(da<<1|1,l,r);
if(tmp2!=-1) return tmp2;
else return tmp1;
}
int n,a[maxn],wz[maxn],ansl[maxn],ansr[maxn],m;
struct jie{
int l,r,id;
}b[maxn];
bool cmp(rg jie aa,rg jie bb){
return aa.r<bb.r;
}
struct asd{
int l,id;
asd(){}
asd(rg int aa,rg int bb){
l=aa,id=bb;
}
friend bool operator <(const asd& A,const asd& B){
if(A.l==B.l) return A.id<B.id;
return A.l>B.l;
}
};
std::set<asd> s;
int main(){
n=read();
for(rg int i=1;i<=n;i++) a[i]=read();
for(rg int i=1;i<=n;i++) wz[a[i]]=i;
m=read();
for(rg int i=1;i<=m;i++){
b[i].l=read(),b[i].r=read(),b[i].id=i;
}
std::sort(b+1,b+m+1,cmp);
build(1,1,n);
rg int now=1;
for(rg int i=1;i<=n;i++){
xg(1,1,i,1);
if(a[i]>1 && wz[a[i]-1]<i) xg(1,1,wz[a[i]-1],-1);
if(a[i]<n && wz[a[i]+1]<i) xg(1,1,wz[a[i]+1],-1);
while(now<=m && b[now].r==i){
s.insert(asd(b[now].l,b[now].id));
now++;
}
while(!s.empty()){
rg int tmp1=s.begin()->l,tmp2=s.begin()->id,tmp3;
tmp3=cx(1,1,tmp1);
if(tmp3==-1) break;
s.erase(s.begin());
ansl[tmp2]=tmp3,ansr[tmp2]=i;
}
}
for(rg int i=1;i<=m;i++) printf("%d %d\n",ansl[i],ansr[i]);
return 0;
}

洛谷 P4747 [CERC2017]Intrinsic Interval 线段树维护连续区间的更多相关文章

  1. BZOJ5259/洛谷P4747: [Cerc2017]区间

    BZOJ5259/洛谷P4747: [Cerc2017]区间 2019.8.5 [HZOI]NOIP模拟测试13 C.优美序列 思维好题,然而当成NOIP模拟题↑真的好吗... 洛谷和BZOJ都有,就 ...

  2. 洛谷 P3373 【模板】线段树 2

    洛谷 P3373 [模板]线段树 2 洛谷传送门 题目描述 如题,已知一个数列,你需要进行下面三种操作: 将某区间每一个数乘上 xx 将某区间每一个数加上 xx 求出某区间每一个数的和 输入格式 第一 ...

  3. 洛谷3822 [NOI2017] 整数 【线段树】【位运算】

    题目分析: 首先这题的询问和位(bit)有关,不难想到是用线段树维护位运算. 现在我们压32位再来看这道题. 对于一个加法操作,它的添加位置可以得到,剩下的就是做不超过32的位移.这样根据压位的理论. ...

  4. 洛谷P4425 [HNOI/AHOI2018]转盘(线段树)

    题意 题目链接 Sol 首先猜一个结论:对于每次询问,枚举一个起点然后不断等到某个点出现时才走到下一个点一定是最优的. 证明不会,考场上拍了3w组没错应该就是对的吧... 首先把数组倍长一下方便枚举起 ...

  5. 洛谷P4425 转盘 [HNOI/AHOI2018] 线段树+单调栈

    正解:线段树+单调栈 解题报告: 传送门! 1551又是一道灵巧连题意都麻油看懂的题,,,,所以先解释一下题意好了,,,, 给定一个n元环 可以从0时刻开始从任一位置出发 每次可以选择向前走一步或者在 ...

  6. 洛谷 P3924 康娜的线段树 解题报告

    P3924 康娜的线段树 题目描述 小林是个程序媛,不可避免地康娜对这种人类的"魔法"产生了浓厚的兴趣,于是小林开始教她\(OI\). 今天康娜学习了一种叫做线段树的神奇魔法,这种 ...

  7. 【洛谷 P3834】 可持久化线段树1(主席树)

    题目链接 主席树=可持久化权值线段树. 如果你不会可持久化线段树,请右转 如果你不会权值线段树,请自行脑补,就是线段树维护值域里有多少个数出现. 可持久化线段树是支持查询历史版本的. 我们对每个数都进 ...

  8. [BZOJ5286][洛谷P4425][HNOI2018]转盘(线段树)

    5286: [Hnoi2018]转盘 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 15  Solved: 11[Submit][Status][Di ...

  9. 洛谷P2221 [HAOI2012]高速公路(线段树+概率期望)

    传送门 首先,答案等于$$ans=\sum_{i=l}^r\sum_{j=i}^r\frac{sum(i,j)}{C_{r-l+1}^2}$$ 也就是说所有情况的和除以总的情况数 因为这是一条链,我们 ...

随机推荐

  1. Codeforces Round #622 (Div. 2) B. Different Rules(数学)

    Codeforces Round #622 (Div. 2) B. Different Rules 题意: 你在参加一个比赛,最终按两场分赛的排名之和排名,每场分赛中不存在名次并列,给出参赛人数 n ...

  2. Codeforces Round #645 (Div. 2) C. Celex Update

    题目链接:C.Celex Update 题意: 给你如图所示的图形,问从(x1,y1)−>(x2,y2)路径上的不同的元素和的数量是多少. 题解: 从(1,1)到(3,3) 元素和的1−2−4− ...

  3. AtCoder Beginner Contest 170 D - Not Divisible (数学)

    题意:有一长度为\(n\)的数组,求该数组中有多少元素不能整除其它任一元素的个数. 题解:刚开始写了个分解质因数(我是傻逼),后来发现直接暴力枚举因子即可,注意某个元素出现多次时肯定不满足情况,再特判 ...

  4. .net core面试题

    第1题,什么是ASP net core? 首先ASP net core不是 asp net的升级版本.它遵循了dot net的标准架构, 可以运行于多个操作系统上.它更快,更容易配置,更加模块化,可扩 ...

  5. next v5升级到next v7需要注意的地方

    title: next v5升级到next v7需要注意的地方 date: 2020-03-04 categories: web tags: [hexo,next] 大部分的设置都是一样的,但有一些细 ...

  6. Redis内存管理中的LRU算法

    在讨论Redis内存管理中的LRU算法之前,先简单说一下LRU算法: LRU算法:即Least Recently Used,表示最近最少使用页面置换算法.是为虚拟页式存储管理服务的,是根据页面调入内存 ...

  7. codeforces 876B

    B. Divisiblity of Differences time limit per test 1 second memory limit per test 512 megabytes input ...

  8. C++ part6.5

    1.虚函数表建立和虚函数表指针初始化 虚拟函数表是在编译期就建立了,各个虚拟函数这时被组织成了一个虚拟函数的入口地址的数组.而虚函数表指针是在运行期,也就是构造函数被调用时进行初始化的,这是实现多态的 ...

  9. Single Round Math sdut3260高精度除以低精度

    做高精度除法,从高位开始除..高位除剩下的我们就*10扔给低一位处理,最终余数是在最低位取模得到的 高精除以高精,我们可以这么做,让除数在后面补零,刚好小于被除数,作若干次减法,减的次数加到商里面 然 ...

  10. 图片转tfrecords

    import numpy as np import tensorflow as tf import time import os import cv2 from sklearn.utils impor ...