题意

给定一个长度为 \(n\) 的排列,有 \(q\) 次询问,每次询问一个区间 \([l,r]\) ,找到最小的包含 \([l,r]\) 的区间,满足这个区间包含了一段连续的数字。

\(n\leq 10^5\)

分析

  • 考虑相邻的两个位置 \(i,i+1\),记两个位置的值为 $ x ,y(x< y)$ 如果要出现在答案里,要满足 \(val \in[x,y]\) 都出现。

  • 用权值线段树维护一段权值区间出现位置的最左最右端 \([l,r]\),显然位置 \(p \in[l,r]\) 都要在区间中,线段树优化建边,表示在 \(i,i+1\) 出现时 \([l,r]\) 也要出现。

  • 求强联通分量之后求出每个scc能够到达的最小最大的标号 ,再将每个位置得到的限制放到线段树里查询即可。

  • 容易证明一个区间的答案可以用上述方式构造。因为如果 \(a\leq b\leq c\leq d\) ,同时 \([a,c],[b,d]\) 是本征区间,那么 \([b,c],[a,d]\) 也是本征区间,可以考虑反证。

  • 总时间复杂度为 \(O(nlogn)\)。

代码

#include<bits/stdc++.h>
using namespace std;
#define go(u) for(int i=head[u],v=e[i].to;i;i=e[i].lst,v=e[i].to)
#define rep(i,a,b) for(int i=a;i<=b;++i)
#define pb push_back
inline int gi(){
int x=0,f=1;char ch=getchar();
while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();}
while(isdigit(ch)){x=(x<<3)+(x<<1)+ch-48;ch=getchar();}
return x*f;
}
template<typename T>inline bool Max(T &a,T b){return a<b?a=b,1:0;}
template<typename T>inline bool Min(T &a,T b){return b<a?a=b,1:0;}
const int N=4e5 + 7,inf=0x3f3f3f3f;
int n,m,a[N];
#define Ls o<<1
#define Rs o<<1|1
struct data{
int l,r;
data(){l=inf;}data(int l,int r):l(l),r(r){}
data operator +(const data &rhs)const{
return data(min(l,rhs.l),max(r,rhs.r));
}
};
struct sgt{
data t[N];
void pushup(int o){
t[o]=t[Ls]+t[Rs];
}
void modify(int p,int l,int r,int o,data v){
if(l==r){
t[o]=v;
return;
}int mid=l+r>>1;
if(p<=mid) modify(p,l,mid,Ls,v);
else modify(p,mid+1,r,Rs,v);
pushup(o);
}
data query(int L,int R,int l,int r,int o){
if(L<=l&&r<=R) return t[o];
int mid=l+r>>1;
if(R<=mid) return query(L,R,l,mid,Ls);
if(L>mid) return query(L,R,mid+1,r,Rs);
return query(L,R,l,mid,Ls)+query(L,R,mid+1,r,Rs);
}
}t[2];
int head[N],pos[N],edc;
struct edge{
int lst,to;
edge(){}edge(int lst,int to):lst(lst),to(to){}
}e[N*30];
void Add(int a,int b){
e[++edc]=edge(head[a],b),head[a]=edc;
}
void build(int l,int r,int o){
if(l==r) {
pos[l]=o;
return;
}
int mid=l+r>>1;
Add(o,Ls);Add(o,Rs);
build(l,mid,Ls);
build(mid+1,r,Rs);
}
void modify(int L,int R,int l,int r,int o,int v){
if(L<=l&&r<=R) { Add(v,o); return;}
int mid=l+r>>1;
if(L<=mid) modify(L,R,l,mid,Ls,v);
if(R>mid) modify(L,R,mid+1,r,Rs,v);
} vector<int>G[N];
int low[N],pre[N],st[N],scc[N],tp,tim,scc_cnt;
int vis[N];
data t1[N],t2[N];
void tarjan(int u){
low[u]=pre[u]=++tim,st[++tp]=u;
go(u){
if(!low[v]){
tarjan(v);
Min(pre[u],pre[v]);
}else if(!scc[v]) Min(pre[u],low[v]);
}
if(low[u]==pre[u]&&++scc_cnt)
for(int x=-1;x^u;)
scc[x=st[tp--]]=scc_cnt;
}
void dfs(int u){
if(vis[u]) return;
vis[u]=1;
for(auto v:G[u]){
dfs(v);
t2[u]=t2[u]+t2[v];
}
}
int main(){
n=gi();
rep(i,1,n) a[i]=gi();
rep(i,1,n) t[0].modify(a[i],1,n,1,data(i,i)); build(1,n,1); rep(i,2,n){
int x=min(a[i-1],a[i]),y=max(a[i-1],a[i]);
t1[ pos[i] ]=t[0].query(x,y,1,n,1);
modify(t1[ pos[i] ].l+1,t1[ pos[i] ].r,1,n,1,pos[i]);
} rep(i,1,N-1) if(!scc[i]) tarjan(i);
rep(u,1,N-1) go(u) if(scc[u]^scc[v]) G[scc[u]].pb(scc[v]);
rep(i,1,N-1) t2[scc[i]]=t2[scc[i]]+t1[i];
rep(i,1,scc_cnt) dfs(i); rep(i,2,n) t[1].modify(i,1,n,1,t2[scc[pos[i]]]); int q=gi();
while(q--){
int l=gi(),r=gi();
if(l==r) { printf("%d %d\n",l,r); continue; }
data res=t[1].query(l+1,r,1,n,1);
printf("%d %d\n",res.l,res.r);
}
return 0;
}

[CERC2017]Intrinsic Interval[scc+线段树优化建图]的更多相关文章

  1. bzoj5017 [Snoi2017]炸弹 (线段树优化建图+)tarjan 缩点+拓扑排序

    题目传送门 https://lydsy.com/JudgeOnline/problem.php?id=5017 题解 这个题目方法挺多的. 线段树优化建图 线段树优化建图的做法应该挺显然的,一个炸弹能 ...

  2. BZOJ5017 [SNOI2017]炸弹 - 线段树优化建图+Tarjan

    Solution 一个点向一个区间内的所有点连边, 可以用线段树优化建图来优化 : 前置技能传送门 然后就得到一个有向图, 一个联通块内的炸弹可以互相引爆, 所以进行缩点变成$DAG$ 然后拓扑排序. ...

  3. 【BZOJ3681】Arietta 树链剖分+可持久化线段树优化建图+网络流

    [BZOJ3681]Arietta Description Arietta 的命运与她的妹妹不同,在她的妹妹已经走进学院的时候,她仍然留在山村中.但是她从未停止过和恋人 Velding 的书信往来.一 ...

  4. 【ARC069F】Flags 2-sat+线段树优化建图+二分

    Description ​ 数轴上有 n 个旗子,第 ii 个可以插在坐标 xi或者 yi,最大化两两旗子之间的最小距离. Input ​ 第一行一个整数 N. ​ 接下来 N 行每行两个整数 xi, ...

  5. 【bzoj5017】[Snoi2017]炸弹 线段树优化建图+Tarjan+拓扑排序

    题目描述 在一条直线上有 N 个炸弹,每个炸弹的坐标是 Xi,爆炸半径是 Ri,当一个炸弹爆炸时,如果另一个炸弹所在位置 Xj 满足:  Xi−Ri≤Xj≤Xi+Ri,那么,该炸弹也会被引爆.  现在 ...

  6. 【bzoj4699】树上的最短路(树剖+线段树优化建图)

    题意 给你一棵 $n$ 个点 $n-1$ 条边的树,每条边有一个通过时间.此外有 $m$ 个传送条件 $(x_1,y_1,x_2,y_2,c)$,表示从 $x_1$ 到 $x_2$ 的简单路径上的点可 ...

  7. 【BZOJ4276】[ONTAK2015]Bajtman i Okrągły Robin 线段树优化建图+费用流

    [BZOJ4276][ONTAK2015]Bajtman i Okrągły Robin Description 有n个强盗,其中第i个强盗会在[a[i],a[i]+1],[a[i]+1,a[i]+2 ...

  8. 【bzoj3073】[Pa2011]Journeys 线段树优化建图+堆优化Dijkstra

    题目描述 Seter建造了一个很大的星球,他准备建造N个国家和无数双向道路.N个国家很快建造好了,用1..N编号,但是他发现道路实在太多了,他要一条条建简直是不可能的!于是他以如下方式建造道路:(a, ...

  9. 【bzoj4383】[POI2015]Pustynia 线段树优化建图+差分约束系统+拓扑排序

    题目描述 给定一个长度为n的正整数序列a,每个数都在1到10^9范围内,告诉你其中s个数,并给出m条信息,每条信息包含三个数l,r,k以及接下来k个正整数,表示a[l],a[l+1],...,a[r- ...

随机推荐

  1. C#多线程的用法10-线程池

    TheadPool:在进行多线程编程时,如果不想频繁的创建线程,那可以考虑使用使用线程池来完成多线程编程的工作.你只需将要处理的任务交付给ThreadPool,如果ThreadPool中有空闲的线程, ...

  2. Percona Xtradb Cluster的设计与实现

    Percona Xtradb Cluster的设计与实现   Percona Xtradb Cluster的实现是在原mysql代码上通过Galera包将不同的mysql实例连接起来,实现了multi ...

  3. SQL Server中事务transaction如果没写在try catch中,就算中间语句报错还是会提交

    假如我们数据库中有两张表Person和Book Person表: CREATE TABLE [dbo].[Person]( ,) NOT NULL, ) NULL, ) NULL, [CreateTi ...

  4. 转:Sql Server中的表访问方式Table Scan, Index Scan, Index Seek

    0.参考文献 Table Scan, Index Scan, Index Seek SQL SERVER – Index Seek vs. Index Scan – Diffefence and Us ...

  5. Windows窗体数据抓取详解

    最近在客户项目上刚好遇到一个问题,项目需求是要获取某台机床的实时状态,问题点刚好就在于该机床不是传统意义上的数控机床,也不是PLC控制器,只有一个上传下载程序文件的应用程序,上面刚好有几个按钮可以大概 ...

  6. PyCharm导入模块报No model named

    PyCharm导入模块报No model named 引言 在PyCharm中同目录下import其他模块,出现No model named ...的报错,但实际可以运行的情况. 这很可能是因为PyC ...

  7. Alpha课堂展示(麻瓜制造者)

    目录 成员简介 演示动态图 预期用户量 演示动态图 目标用户视频 分工协作 项目管理 质量控制 团队角色与具体贡献 用户反馈 成员简介 刘双玉 http://www.cnblogs.com/liu42 ...

  8. python textwrap.md

    textwrap textwrap模块可以用来格式化文本, 使其在某些场合输出更美观. 他提供了一些类似于在很多文本编辑器中都有的段落包装或填充特性的程序功能. Example Data 本节中的示例 ...

  9. An Introduction to Protocol Oriented Programming in Swift

    swift面向协议编程的根本原因在于值类型的存在:面向对象必须要有引用类型的支持: Protocol Oriented approach was introduced to resolve some ...

  10. linux,添加新硬盘的方法

    一.物理机添加一块新的硬盘方法(目的是把后加的磁盘直接加在现有的上面,不用再分区挂载)1.首先要确定现有系统在那块盘上  [root@localhost ~]# df -lhFilesystem    ...