递增#题意
给定n个二元组(xi,yi),两个二元组i和j的价值定义为|xi−xj|∗max{yi,yj}
一个区间[L,R]的价值是其中任选两个二元组的最大价值。
给定m个操作,修改一个二元组的x或y,询问一个区间的价值。
n,m<=10^5。
数据保证初始的y和修改的y随机生成。
有理有据期望复杂度
考虑一个1..n的随机排列,他与一棵笛卡尔树唯一双向映射。
相当于在笛卡尔树的所有形态中随机选取,因此树高与随机二叉树相同,都是期望log.
根据笛卡尔树树高log这个结论,可以得出递减序列长度也期望是log.(取最左最右,往上走可得)
维护左右第一个比它大的。
查询,发现有用的点一定在递增递减序列上。也就是log个,根据单调性log求一下max.
修改a,可以发现有改动的点一定在a-1的左链上,a+1的右链上。
根据单调性调整一下lmax,rmax即可。
时间复杂度: n log n
#include <cstdio>
#include <iostream>
using namespace std;
typedef long long ll;
const int N=5e5+10;
int n,q;
ll x[N],y[N],lm[N],rm[N];
int Q[N];
int main() {
freopen("board.in","r",stdin);
freopen("board.out","w",stdout);
cin>>n>>q;
for (int i=1; i<=n; i++) scanf("%lld",&x[i]);
for (int i=1; i<=n; i++) scanf("%lld",&y[i]);
for (int i=1; i<=n; i++) {
while (Q[0] && y[Q[Q[0]]]<=y[i]) {
rm[Q[Q[0]]]=i;
Q[0]--;
}
Q[++Q[0]]=i;
}
Q[0]=0;
for (int i=n; i; i--) {
while (Q[0] && y[Q[Q[0]]]<=y[i]) {
lm[Q[Q[0]]]=i;
Q[0]--;
}
Q[++Q[0]]=i;
}
for (int i=1; i<=q; i++) {
ll ty,a,b; scanf("%lld %lld %lld",&ty,&a,&b);
if (ty==1) {
ll g=a,d=b,ans=0;
for (;g && g<=b;g=rm[g]) {
while (d && d>=a && y[d]<y[g]) d=lm[d];
if (d==0 || g>=d) break;
ans=max(ans,(x[d]-x[g])*y[g]);
}
g=a,d=b;
for (;d>=a;d=lm[d]) {
while (g && g<=b && y[g]<y[d]) g=rm[g];
if (g==0 || g>=d) break;
ans=max(ans,(x[d]-x[g])*y[d]);
}
printf("%lld\n",ans);
} else if (ty==2) {
y[a]=b;
lm[a]=rm[a]=0;
for (int i=a-1; i; i=lm[i]) if (y[i]>y[a]) {
lm[a]=i; break;
}
for (int i=a+1; i; i=rm[i]) if (y[i]>y[a]) {
rm[a]=i; break;
}
int now=a+1;
for (int i=a-1; i; i=lm[i]) {
while (now && y[now]<=y[i]) now=rm[now];
rm[i]=y[a]>=y[i] ? a : now;
}
now=a-1;
for (int i=a+1; i; i=rm[i]) {
while (now && y[now]<=y[i]) now=lm[now];
lm[i]=y[a]>=y[i] ? a : now;
}
} else x[a]=b;
}
}