洛谷 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}$$ 也就是说所有情况的和除以总的情况数 因为这是一条链,我们 ...
随机推荐
- CF-gym/101810 J、T-Shirts Dilemma
题目链接:点我 题意: 给你一个区间[a,b],让你从里面选一个连续子区间[x,y](子区间可以为[a,b]),把这个区间的所有数或起来x|x+1|x+2|...|y 你要使得区间[x,y]异或起来的 ...
- Codeforces Round #579 (Div. 3) D2. Remove the Substring (hard version) (思维,贪心)
题意:给你一个模式串\(t\),现在要在主串\(s\)中删除多个子串,使得得到的\(s\)的子序列依然包含\(t\),问能删除的最长子串长度. 题解:首先,我们不难想到,我们可以选择\(s\)头部到最 ...
- 571A Lengthening Sticks
time limit per test 1 second memory limit per test 256 megabytes input standard input output standar ...
- Codeforces Round #295 (Div. 2) B. Two Buttons (DP)
题意:有两个正整数\(n\)和\(m\),每次操作可以使\(n*=2\)或者\(n-=1\),问最少操作多少次使得\(n=m\). 题解:首先,若\(n\ge m\),直接输出\(n-m\),若\(2 ...
- Pyqt5 安装
window 安装PyQt5 pip install pyqt5 pip install pyqt5-tools (安装常用的Qt工具) 添加环境变量 变量名: QT_QPA_PLATFORM_PL ...
- 1.ASP.NET Core 管道、中间件、依赖注入
自定义中间件(基于工厂) 自定义中间件(注入到第三方容器)
- MATLAB中将mat文件转为txt格式文件
直接保存为txt文件: 可以用fprintf函数,来代替save函数 比如现在我有一个变量a=[0.1223 345.4544] 如果我想保存它的话,可以用下面的程序: fid = fopen(' ...
- BZOJ 3676 回文串(回文树)题解
题意: 一个回文的价值为长度 * 出现次数,问一个串中的子串的最大回文价值 思路: 回文树模板题,跑PAM,然后计算所有节点出现次数. 参考: 回文串问题的克星--Palindrome Tree(回文 ...
- Web 页面生命周期 All In One
Web 页面生命周期 All In One Web Page LifeCycle All In One refs xgqfrms 2012-2020 www.cnblogs.com 发布文章使用:只允 ...
- short URL 短网址实现原理剖析
short URL 短网址实现原理剖析 意义,简短便于分享,避免出现超长 URL 的字符长度限制问题 原理分析, 使用 HashMap 存储对应的映射关系 (长度不超过7的字符串,由大小写字母加数字共 ...