洛谷 P4747 [CERC2017]Intrinsic Interval 线段树维护连续区间
题目描述
分析
考虑对于 \([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 线段树维护连续区间的更多相关文章
- BZOJ5259/洛谷P4747: [Cerc2017]区间
BZOJ5259/洛谷P4747: [Cerc2017]区间 2019.8.5 [HZOI]NOIP模拟测试13 C.优美序列 思维好题,然而当成NOIP模拟题↑真的好吗... 洛谷和BZOJ都有,就 ...
- 洛谷 P3373 【模板】线段树 2
洛谷 P3373 [模板]线段树 2 洛谷传送门 题目描述 如题,已知一个数列,你需要进行下面三种操作: 将某区间每一个数乘上 xx 将某区间每一个数加上 xx 求出某区间每一个数的和 输入格式 第一 ...
- 洛谷3822 [NOI2017] 整数 【线段树】【位运算】
题目分析: 首先这题的询问和位(bit)有关,不难想到是用线段树维护位运算. 现在我们压32位再来看这道题. 对于一个加法操作,它的添加位置可以得到,剩下的就是做不超过32的位移.这样根据压位的理论. ...
- 洛谷P4425 [HNOI/AHOI2018]转盘(线段树)
题意 题目链接 Sol 首先猜一个结论:对于每次询问,枚举一个起点然后不断等到某个点出现时才走到下一个点一定是最优的. 证明不会,考场上拍了3w组没错应该就是对的吧... 首先把数组倍长一下方便枚举起 ...
- 洛谷P4425 转盘 [HNOI/AHOI2018] 线段树+单调栈
正解:线段树+单调栈 解题报告: 传送门! 1551又是一道灵巧连题意都麻油看懂的题,,,,所以先解释一下题意好了,,,, 给定一个n元环 可以从0时刻开始从任一位置出发 每次可以选择向前走一步或者在 ...
- 洛谷 P3924 康娜的线段树 解题报告
P3924 康娜的线段树 题目描述 小林是个程序媛,不可避免地康娜对这种人类的"魔法"产生了浓厚的兴趣,于是小林开始教她\(OI\). 今天康娜学习了一种叫做线段树的神奇魔法,这种 ...
- 【洛谷 P3834】 可持久化线段树1(主席树)
题目链接 主席树=可持久化权值线段树. 如果你不会可持久化线段树,请右转 如果你不会权值线段树,请自行脑补,就是线段树维护值域里有多少个数出现. 可持久化线段树是支持查询历史版本的. 我们对每个数都进 ...
- [BZOJ5286][洛谷P4425][HNOI2018]转盘(线段树)
5286: [Hnoi2018]转盘 Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 15 Solved: 11[Submit][Status][Di ...
- 洛谷P2221 [HAOI2012]高速公路(线段树+概率期望)
传送门 首先,答案等于$$ans=\sum_{i=l}^r\sum_{j=i}^r\frac{sum(i,j)}{C_{r-l+1}^2}$$ 也就是说所有情况的和除以总的情况数 因为这是一条链,我们 ...
随机推荐
- C# Dictionary(字典)源码解析&效率分析
通过查阅网上相关资料和查看微软源码,我对Dictionary有了更深的理解. Dictionary,翻译为中文是字典,通过查看源码发现,它真的内部结构真的和平时用的字典思想一样. 我们平时用的字典主要 ...
- Linux入门详解
Linux基础知识 Linux&Unix 说起Linux,就不得不提Unix操作系统. Unix系统号称世界上最稳定的系统,就连苹果公司也从中获取灵感开发出了移动端大名鼎鼎的IOS. Unix ...
- Linunx系统引导过程及MBR/GRUB故障
Linunx系统引导过程 系统初始化进程 init进程 Systemd Systemd单元类型 允许级别所对应的systemd目标 修复MBR扇区故障 解决思路 操作 修复GRUB引导故障 解决思路 ...
- woj1008feedinganimals2-贪心-网络流
title: woj1008feedinganimals2-贪心-网络流 date: 2020-03-07 categories: acm tags: [acm,woj,网络流,贪心] 中等题. 标准 ...
- windows cmd 查看远程连接端口
查看远程端口号 Cmd tasklist /svc 在输出的内容中查找svchost.exe进程下termservice服务对应的PID,在此查看的PID为:276 然后输入命令:netstat ...
- 基于HSV彩色空间与直方图信息的植物叶脉FFCM算法提取
宣旭峰,王美丽,张建锋. 基于HSV彩色空间与直方图信息的植物叶脉FFCM算法提取[J/OL]. 计算机应用研究,2018,(08):1-7. (2017-07-21)[2017-10-09]. ht ...
- 二分类问题中混淆矩阵、PR以及AP评估指标
仿照上篇博文对于混淆矩阵.ROC和AUC指标的探讨,本文简要讨论机器学习二分类问题中的混淆矩阵.PR以及AP评估指标:实际上,(ROC,AUC)与(PR,AP)指标对具有某种相似性. 按照循序渐进的原 ...
- vue v-on-clickaway
vue v-on-clickaway Custom directive 自定义指令 https://stackoverflow.com/questions/36170425/detect-click- ...
- 一个最简单 node.js 命令行工具
一个最简单 node.js 命令行工具 node.js cli $ node cli.js xyz # OR $ node cli xyz 接受参数 process.argv js "use ...
- Chrome DevTools & Slow 3G Network
Chrome DevTools & Slow 3G Network shortcuts https://developers.google.com/web/tools/chrome-devto ...