【题解】QOJ 894 Longest Loose Segment
QOJ 894 Longest Loose Segment
题意
给定一个长度为 \(n\) 的序列 \(a\),求出满足如下条件的区间的最长长度是多少:
- \(\displaystyle \min_{i\in [l,r]} a_i+\max_{i\in [l,r]} a_i>r-l+1\)。
有 \(m\) 组额外测试,每次在原数组的基础上交换若干元素的位置。
\(n\le 10^6,m\le 30\)。
题解
知识点:笛卡尔树,动态规划。
被击杀了。
很显然这题卡对数做法,但是可以简要提一嘴。
使用最值分治,钦定最大值后,另外两项关于区间长度的变化具有显然的单调性,进而推出可二分性,做到 \(O(mn\log^2 n)\),其中一个 \(\log\) 常数很小。
其实也可以直接二分答案,只指定区间长度时(不指定具体位置),最大的 \(\max+\min\) 也是有单调性的,check 就只需要模拟一下了。
可惜模拟赛时没能想到这个简单做法,但无伤大雅,还是得到了这档分,不过没能感觉到这个单调性,我还是需要好好反思。
考虑线性做法,可以在笛卡尔树上 dp。
建出小根笛卡尔树,对于节点 \(u\) 计算 \(u\) 子树代表区间中的最长合法区间长度。
接下来按区间是否经过 \(u\) 进行分讨,对于不经过的情况,只需要从儿子转移过来就行了。
对于经过的情况,区间的 \(\min\) 就已经确定为了 \(a_u\)。
发现这部分的计算不太好直接做,考虑找一下性质。
\(a_u\) 是区间的最小值,一个区间经过它会使得 \(\min+\max\) 更小,那么需要琢磨一下怎样的最优区间会经过 \(u\)。
考虑一个拓展的过程(这里拿左子树举例),一个在左子树里的合法区间 \([l,r]\),通过拓展 \(k\) 个位置,使得右端点 \(\ge u\),稍加分析,如果这个过程满足最优性,那么右端点 \(\ge u\) 的必要条件就是左端点已经拓展到了最左端,因为左边不存在比 \(a_u\) 更小的数,先往左拓展一定是不劣的。
那么结论就很显然了,经过 \(u\) 的最优区间一定至少包含了 \(u\) 的左右子树之一。
那么 \(\max\) 可以取子树的 \(\max\),依据 \(\max+\min>len\),得到 \(\max+\min-1\ge len\),可以计算得出合法区间长度的上界,显然长度越长越好,但是要和 \(u\) 子树的实际区间长度取 \(\min\),且这个上界要比其儿子子树区间长度长。
更多没有提及的细节可以阅读代码。
#include<bits/stdc++.h>
using namespace std;
#define rep(i,l,r) for(int i=(l);i<=(r);++i)
#define per(i,l,r) for(int i=(r);i>=(l);--i)
#define pr pair<int,int>
#define fi first
#define se second
#define pb push_back
#define all(x) (x).begin(),(x).end()
#define bg(x) (x).begin()
#define ed(x) (x).end()
#define sz(x) (int)(x).size()
#define N 1002511
// #define int long long
int n,m,a[N],l[N],r[N];
int st[N],tp,rt;
int f[N],len[N],mx[N];
inline void buildl(){
tp=0;
rep(i,1,n){
int u=0;
while(tp&&a[st[tp]]>a[i]){
u=st[tp];
tp--;
}
l[i]=u;
st[++tp]=i;
}
}
inline void buildr(){
tp=0;
per(i,1,n){
int u=0;
while(tp&&a[st[tp]]>=a[i]){
u=st[tp];
tp--;
}
r[i]=u;
st[++tp]=i;
}
}
inline void dfs(int k){
int v=a[k];
len[k]=1;
mx[k]=v;
f[k]=(2*a[k])>1;
if(l[k]){
dfs(l[k]);
len[k]+=len[l[k]];
mx[k]=max(mx[k],mx[l[k]]);
f[k]=max(f[k],f[l[k]]);
int re=mx[l[k]]+v-1;
if(re>len[l[k]]){
f[k]=max(f[k],re);
}
}
if(r[k]){
dfs(r[k]);
len[k]+=len[r[k]];
mx[k]=max(mx[k],mx[r[k]]);
f[k]=max(f[k],f[r[k]]);
int re=mx[r[k]]+v-1;
if(re>len[r[k]]){
f[k]=max(f[k],re);
}
}
f[k]=min(f[k],len[k]);
}
inline int sol(){
buildl();
buildr();
rt=1;
rep(i,1,n){
if(a[i]<a[rt]){
rt=i;
}
}
dfs(rt);
return f[rt];
}
signed main(){
// freopen(".in","r",stdin);
// freopen(".out","w",stdout);
ios::sync_with_stdio(0);
cin.tie(0);cout.tie(0);
cin>>n>>m;
rep(i,1,n){
cin>>a[i];
}
cout<<sol()<<'\n';
rep(i,1,m){
int c;
cin>>c;
rep(j,1,c){
int x,y;
cin>>x>>y;
swap(a[x],a[y]);
}
cout<<sol()<<'\n';
}
return 0;
}

浙公网安备 33010602011771号