Codeforces 1332G - No Monotone Triples(数据结构综合)
首先打表即可发现对于任意长度 \(\ge 5\) 的序列总存在一个 Monotone triple,证明不会实在不行直接 \(5^5\) 枚举相对位置大小都可以发现,因此答案要么是 \(0\),要么是 \(3\),要么是 \(4\),我们考虑对三种情况分别分类讨论,即检查区间内是否存在长度为 \(3\) 的 Monotone triple free 的子序列,再检查区间内是否存在长度为 \(4\) 的 Monotone triple free 的子序列,这样即可确定答案。
因此我们可以大致将题目分为两个部分:
1. 检验区间中是否存在长度为 \(3\) 的 Monotone triple free 的子序列
首先显然三个位置 \(i,j,k(i<j<k)\) 能够构成 Monotone triple free 的序列当且仅当中间位置的值严格小于边上两个数的值,或者中间位置的值严格大于边上两个数的值。
考虑枚举中间位置 \(p\),我们贪心地想,我们希望这三个位置都在区间 \([l,r]\) 中,因此边上两个位置肯定离中间位置越紧凑越好,因此我们可以先预处理出四个数组:\(mxl_i\) 表示在 \(i\) 前面且大于 \(a_i\) 的离 \(i\) 最近的位置,\(mxr_i\) 表示在 \(i\) 后面且大于 \(a_i\) 的离 \(i\) 最近的位置,\(mnl_i,mnr_i\) 也可以类似地定义,单调栈可以求出。那么对于以 \(p\) 为中心的长度为 \(3\) 的序列,\((mnl_p,p,mnr_p),(mxl_p,p,mxr_p)\) 必然都是的 Monotone triple free 的序列,并且这两个序列分别是上述两种情况中最紧凑的序列——如果它们都不能包含在 \([l,r]\) 中那么所有以 \(p\) 为中心的长度为 \(3\) 的 Monotone triple free 序列肯定都不能包含在 \([l,r]\) 中了。
因此题目转化为,是否 \(\exists p\in[l,r]\) 满足 \(mnl_p\ge l,mnr_p\le r\) 或者 \(mxl_p\ge l,mxr_p\le r\)。考虑一个离线做法,我们将所有询问都挂在 \(l\) 处,然后开一个指针 \(i\) 从右到左扫描,再建立一棵线段树,每次当指针从 \(i+1\) 变到 \(i\) 时都枚举所有 \(mnl_p=i\) 的 \(p\) 并用 \(mnr_p\) 更新线段树上 \(p\) 位置上的值,\(mxl\) 也同理,回答询问时只需检验线段树上 \([l,r]\) 位置上的最小值是否 \(\le r\) 即可,输出方案只需再记录一个取到最小值的位置再稍微分下类即可。
时间复杂度 \(n\log n\)
2. 检验区间中是否存在长度为 \(4\) 的 Monotone triple free 的子序列
这个看起来有亿点点棘手,因此我们先来挖掘下性质,对于一个长度为 \(4\) 的序列而言,如果它的最大值不唯一那肯定不合法——如果这两个最大值有一个在中间两个位置就肯定存在一个三元组满足左边两个数或右边两个数相同,否则不论中间两个数大小关系如何也都会存在 monotone triple。因此这四个数只能有唯一的最大值和最小值,而如果这唯一的最大值/最小值在两边,不妨以最大值在第一个位置为例,如果后三个数存在逆序对那这个最大值与这个逆序对就存在 monotone triple,否则这三个数就构成了 monotone triple,因此四个数构成 Monotone triple free 序列的充要条件是:存在唯一的最大/小值,并且最大/小值分别在第二、三个位置。
我们考虑固定第一、四个位置 \(i,l\),那么我们肯定会选择区间 \((i,l)\) 的最大值&最小值作为第二、三个位置,即存在合法的序列当且仅当区间 \((i,l)\) 的最大值 \(>\max(a_i,a_l)\),且最小值 \(<\min(a_i,a_l)\),直接枚举肯定行不通。我们考虑预处理 \(r3_i\) 表示最小的 \(r\) 满足 \((i,r]\) 最大值 \(>a_i\) 且最小值 \(<a_i\),\(l3_i\) 表示最大的 \(l\) 满足 \([l,i)\) 最大值 \(>a_i\) 且最小值 \(<a_i\),这个可以二分+ST 表,也可以直接调用上面求出的 \(mnl_i,mnr_i,mxl_i,mxr_i\),那么当我们固定住 \(i\) 之后,合法的 \(l\) 必须 \(>r3_i\),并且 \(l3_l>i\)。
我们再求出 \(r4_i\) 表示最小的 \(l\) 满足 \(l>r3_i,l3_l>i\),这个可以通过对 \(l3\) 数组建 ST 表之后二分求出,那么 \(i,r4_i\) 恰好分别对应一个长度为 \(4\) 的 Monotone triple free 序列的 \(i,l\),并且这肯定是以 \(i\) 为第一个元素的最后一个位置下标最小的合法序列,因此对于每个询问我们需检验是否存在一个 \(i\in[l,r]\) 满足 \(r4_i\le r\),这个可以再对 \(r4\) 建 ST 表求出。最后输出方案可以维护一个取到最小值的位置求出边上两个元素,再根据这两个位置之间最大值、最小值的位置求出中间两个元素。
时间复杂度 \(n\log n\)。
那么问题就来了,为什么求长度为 \(3\) 的序列时离线了,求长度为 \(4\) 的序列时反而没有离线呢
const int MAXN=2e5;
const int LOG_N=17;
const int INF=0x3f3f3f3f;
int n,qu,a[MAXN+5],L[MAXN+5],R[MAXN+5];
vector<pii> ql[MAXN+5];
int mnl[MAXN+5],mxl[MAXN+5],mnr[MAXN+5],mxr[MAXN+5];
namespace solve3{
vector<pii> pl[MAXN+5];
tuple<int,int,int> ans[MAXN+5];
struct node{int l,r;pii val;} s[MAXN*4+5];
pii merge(pii x,pii y){
pii ret;ret.fi=min(x.fi,y.fi);
if(ret.fi==x.fi) ret.se=x.se;
else ret.se=y.se;
return ret;
}
void pushup(int k){s[k].val=merge(s[k<<1].val,s[k<<1|1].val);}
void build(int k,int l,int r){
s[k].l=l;s[k].r=r;if(l==r){s[k].val=mp(INF,l);return;}
int mid=l+r>>1;build(k<<1,l,mid);build(k<<1|1,mid+1,r);pushup(k);
}
void modify(int k,int x,int v){
if(s[k].l==s[k].r) return chkmin(s[k].val.fi,v),void();
int mid=s[k].l+s[k].r>>1;
(x<=mid)?modify(k<<1,x,v):modify(k<<1|1,x,v);
pushup(k);
}
pii query(int k,int l,int r){
if(l<=s[k].l&&s[k].r<=r) return s[k].val;
int mid=s[k].l+s[k].r>>1;
if(r<=mid) return query(k<<1,l,r);
else if(l>mid) return query(k<<1|1,l,r);
else return merge(query(k<<1,l,mid),query(k<<1|1,mid+1,r));
}
void solve(){
build(1,1,n);
for(int i=1;i<=n;i++) pl[mxl[i]].pb(mp(i,mxr[i]));
for(int i=1;i<=n;i++) pl[mnl[i]].pb(mp(i,mnr[i]));
// for(int i=1;i<=n;i++) printf("%d %d %d %d\n",mnl[i],mxl[i],mnr[i],mxr[i]);
for(int i=n;i;i--){
for(pii p:pl[i]) modify(1,p.fi,p.se);
for(pii p:ql[i]){
int x=p.fi,id=p.se;
pii mn=query(1,i,x);
if(mn.fi<=x){
int pos=mn.se;
if(mnl[pos]>=i&&mnr[pos]<=x) ans[id]=make_tuple(mnl[pos],pos,mnr[pos]);
if(mxl[pos]>=i&&mxr[pos]<=x) ans[id]=make_tuple(mxl[pos],pos,mxr[pos]);
}
}
}
}
}
namespace solve4{
template<typename T> struct st_table{
T v[MAXN+5][LOG_N+2];int op;
void build(){
for(int i=1;i<=LOG_N;i++) for(int j=1;j+(1<<i)-1<=n;j++)
v[j][i]=(op)?max(v[j][i-1],v[j+(1<<i-1)][i-1]):min(v[j][i-1],v[j+(1<<i-1)][i-1]);
}
T query(int l,int r){
int k=31-__builtin_clz(r-l+1);
return (op)?max(v[l][k],v[r-(1<<k)+1][k]):min(v[l][k],v[r-(1<<k)+1][k]);
}
};
st_table<int> st3;
st_table<pii> mn,mx,st4;
int l3[MAXN+5],r3[MAXN+5],r4[MAXN+5];
tuple<int,int,int,int> ans[MAXN+5];
void solve(){
mx.op=st3.op=1;
for(int i=1;i<=n;i++) mn.v[i][0]=mx.v[i][0]=mp(a[i],i);
mn.build();mx.build();
for(int i=1;i<=n;i++){
r3[i]=max(mxr[i],mnr[i]);
l3[i]=min(mxl[i],mnl[i]);
st3.v[i][0]=l3[i];
} st3.build();
for(int i=1;i<=n;i++){
int l=r3[i]+1,r=n,p=n+1;
while(l<=r){
int mid=l+r>>1;
if(st3.query(r3[i]+1,mid)>i) p=mid,r=mid-1;
else l=mid+1;
} r4[i]=p;st4.v[i][0]=mp(r4[i],i);
// printf("%d\n",r4[i]);
} st4.build();
for(int i=1;i<=qu;i++){
pii p=st4.query(L[i],R[i]);
// printf("%d\n",p.fi);
if(p.fi<=R[i]){
int i1=p.se,i4=p.fi;
int i2=mn.query(i1,i4).se,i3=mx.query(i1,i4).se;
if(i2>i3) i2^=i3^=i2^=i3;
// printf("%d %d %d %d\n",i1,i2,i3,i4);
ans[i]=make_tuple(i1,i2,i3,i4);
}
}
}
}
int main(){
scanf("%d%d",&n,&qu);
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
stack<int> stk;
for(int i=1;i<=n;i++){
while(!stk.empty()&&a[stk.top()]<=a[i]) stk.pop();
mxl[i]=((stk.empty())?0:stk.top());stk.push(i);
} while(!stk.empty()) stk.pop();
for(int i=1;i<=n;i++){
while(!stk.empty()&&a[stk.top()]>=a[i]) stk.pop();
mnl[i]=((stk.empty())?0:stk.top());stk.push(i);
} while(!stk.empty()) stk.pop();
for(int i=n;i;i--){
while(!stk.empty()&&a[stk.top()]<=a[i]) stk.pop();
mxr[i]=((stk.empty())?n+1:stk.top());stk.push(i);
} while(!stk.empty()) stk.pop();
for(int i=n;i;i--){
while(!stk.empty()&&a[stk.top()]>=a[i]) stk.pop();
mnr[i]=((stk.empty())?n+1:stk.top());stk.push(i);
} while(!stk.empty()) stk.pop();
for(int i=1;i<=qu;i++) scanf("%d%d",&L[i],&R[i]),ql[L[i]].pb(mp(R[i],i));
solve3::solve();solve4::solve();
for(int i=1;i<=qu;i++){
if(!get<0>(solve3::ans[i])) printf("0\n");
else if(!get<0>(solve4::ans[i]))
printf("3\n%d %d %d\n",get<0>(solve3::ans[i]),get<1>(solve3::ans[i]),get<2>(solve3::ans[i]));
else printf("4\n%d %d %d %d\n",get<0>(solve4::ans[i]),get<1>(solve4::ans[i]),get<2>(solve4::ans[i]),get<3>(solve4::ans[i]));
}
return 0;
}
Codeforces 1332G - No Monotone Triples(数据结构综合)的更多相关文章
- 20162327WJH实验五——数据结构综合应用
20162327WJH实验五--数据结构综合应用 实 验 报 告 课程:程序设计与数据结构 班级: 1623 姓名: 王旌含 学号:20162327 成绩: 指导教师:娄嘉鹏 王志强 实验密级: 非密 ...
- 【Codeforces 722C】Destroying Array (数据结构、set)
题意 输入一个含有 n(1≤n≤100000) 个非负整数的 a 数组和一个 1-n 的排列 p 数组,求每次删除 a[p[i]] 后,最大连续子段和(不能跨越被删除的)是多少? 分析 因为都是非负整 ...
- codeforces 707C C. Pythagorean Triples(数学)
题目链接: C. Pythagorean Triples time limit per test 1 second memory limit per test 256 megabytes input ...
- 【codeforces 707C】Pythagorean Triples
[题目链接]:http://codeforces.com/contest/707/problem/C [题意] 给你一个数字n; 问你这个数字是不是某个三角形的一条边; 如果是让你输出另外两条边的大小 ...
- 【Codeforces 707C】Pythagorean Triples(找规律)
一边长为a的直角三角形,a^2=c^2-b^2.可以发现1.4.9.16.25依次差3.5.7.9...,所以任何一条长度为奇数的边a,a^2还是奇数,那么c=a^2/2,b=c+1.我们还可以发现, ...
- 洛谷 P4497 - [WC2011]拼点游戏(数据结构综合)
题面传送门 神仙 DS. 首先关于第一问可以轻松想到一个 DP,\(dp_{i,j}\) 表示考虑到第 \(i\) 位,这一位奇偶性为 \(j\) 的最大权值,时间复杂度 \(n^2q\),可以拿到 ...
- 浅谈算法和数据结构: 七 二叉查找树 八 平衡查找树之2-3树 九 平衡查找树之红黑树 十 平衡查找树之B树
http://www.cnblogs.com/yangecnu/p/Introduce-Binary-Search-Tree.html 前文介绍了符号表的两种实现,无序链表和有序数组,无序链表在插入的 ...
- 20162327WJH2016-2017-2《程序设计与数据结构》课程总结
20162327WJH2016-2017-2<程序设计与数据结构>课程总结 一.每周作业链接汇总 第一周作业:算法分析 第三周作业:查找与排序 第五周作业:有关栈的总结 第七周作业:树的有 ...
- (转)POJ题目分类
初期:一.基本算法: (1)枚举. (poj1753,poj2965) (2)贪心(poj1328,poj2109,poj2586) (3)递归和分治法. (4)递推. ...
随机推荐
- 初学python-day3 列表
- Less-(5~7) error based
Less-5: 核心语句: 我们注意到,当输入正确时,并不能获得有价值的回显.好在出现错误时,会爆出错误内容: 于是,使用报错注入: 1' and updatexml(1,concat(0x7e,( ...
- sql递归查询部门数据
1 with cte as 2 ( 3 select a.DepartCode,a.DepartName,a.ParentDepartCode from tbDeparts a where Paren ...
- OO第四单元
OO第四单元总结 第四单元架构设计 第一次作业 uml类图 这次作业我采取的基本思路就是根据指令来建造一个简易的类图,用于查询,其中umlclass中包含了umlAttraibute,umlOpera ...
- DeWeb配置SSL的方法,未亲测,供参考
DeWeb配置SSL的方法1.购买域名的服务商申明免费的SSL证书,然后证书类型下载选择Nginx2.下载Nginx,http://nginx.org/download/nginx-1.20.0.zi ...
- 使用vsftpd 搭建ftp服务
ftp 基础服务器基础知识 ftp有三种登录方式.匿名登录(所有用户).本地用户.虚拟用户(guest). FTP工作模式 主动模式:服务端从20端口主动向客户端发起链接. 控制端口21:数据传输端口 ...
- 二层组网AP上线
一.实验目的 1)掌握配置WLAN源接口的命令 2)掌握配置DHCP服务器的命令 3)掌握手工确认AP上线的方法a 二.实验仪器设备及软件 仪器设备:一台AC,四台AP 软件:ENSP 三.实验原理 ...
- 面试题系列:用了这么多年的 Java 泛型,我竟然只知道它的皮毛
面试题:说说你对泛型的理解? 面试考察点 考察目的:了解求职者对于Java基础知识的掌握程度. 考察范围:工作1-3年的Java程序员. 背景知识 Java中的泛型,是JDK5引入的一个新特性. 它主 ...
- SpringMVC配置知识点
SpringMVC原生知识点 通过idea新建一个SpringMVC的Project(新建普通的项目就行了) 填写完之后Finish就行了 (实际开发不会这么用,这么做是为了理解!) 然后就是Spri ...
- Part 38 AngularJS cancel route change
n this video we will discuss, how to cancel route change in Angular with an example. This is extreme ...