题解 擒敌拳
单调栈+斜率优化可以有80pts
正解是李超线段树,还不会,咕了
补上了
首先肯定是单调栈,但这里要对每个位置都求值
发现每个位置的决策点一定在栈中且单调向右,于是考虑维护凸包
但凸包在弹栈的时候需要重构,复杂度炸了
于是我们考虑维护一个支持「区间对等差数列取max」的数据结构
转化到二维平面上,就是插入一条线段,对每个位置取最高点
于是可以用李超线段树
- 李超线段树注意一条线段被抛弃的时候要下放
Code:
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define N 200010
#define ll long long
//#define int long long
char buf[1<<21], *p1=buf, *p2=buf;
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf, 1, 1<<21, stdin)), p1==p2?EOF:*p1++)
inline int read() {
int ans=0, f=1; char c=getchar();
while (!isdigit(c)) {if (c=='-') f=-f; c=getchar();}
while (isdigit(c)) {ans=(ans<<3)+(ans<<1)+(c^48); c=getchar();}
return ans*f;
}
int n;
namespace force{
struct que{ll h, pos; inline void build(ll a, ll b) {h=a; pos=b;}}q[N];
void solve() {
int l=1, r=0;
ll ans=0;
for (int i=1; i<=n; ++i) {
ll tem=i, h=read();
while (l<=r && q[r].h>=h) tem=q[r--].pos;
q[++r].build(h, tem);
for (int j=l; j<=r; ++j) ans=max(ans, q[j].h*(i-q[j].pos+1));
printf("%lld ", ans);
}
printf("\n");
}
}
namespace task1{
struct que{ll h, pos; inline void build(ll a, ll b) {h=a; pos=b;}}q[N], q2[N];
inline double calc(double hj, double j, double hk, double k) {return ((hj*j-hj)-(hk*k-hk))/(hj-hk);}
void solve() {
int l=1, r=0, l2=1, r2=0;
ll ans=0;
for (int i=1; i<=n; ++i) {
// cout<<"i: "<<i<<endl;
ll tem=i, h=read();
while (l<=r && q[r].h>=h) tem=q[r--].pos;
q[++r].build(h, tem);
// cout<<"k: "<<calc(q2[l2].h, q2[l2].pos, q2[l2+1].h, q2[l2+1].pos)<<endl;
while (l2<=r2 && q2[r2].h>=h) --r2;
while (l2<r2 && calc(q2[r2-1].h, q2[r2-1].pos, q2[r2].h, q2[r2].pos)>calc(q2[r2].h, q2[r2].pos, h, tem)) --r2;
// cout<<"now: "<<l2<<' '<<r2<<endl;
// cout<<"build: "<<h<<' '<<tem<<endl;
q2[++r2].build(h, tem);
// cout<<"LR: "<<l2<<' '<<r2<<endl;
// cout<<"q2: "; for (int j=l2; j<=r2; ++j) cout<<q2[j].h<<','<<q2[j].pos<<' '; cout<<endl;
// cout<<"k: "<<calc(q2[l2].h, q2[l2].pos, q2[l2+1].h, q2[l2+1].pos)<<endl;
while (l2<r2 && calc(q2[l2].h, q2[l2].pos, q2[l2+1].h, q2[l2+1].pos)<i) ++l2; //, cout<<"testk: "<<calc(q2[l2].h, q2[l2].pos, q2[l2+1].h, q2[l2+1].pos)<<' '<<l2<<' '<<r2<<endl;
ans = max(ans, q2[l2].h*(i-q2[l2].pos+1));
// for (int j=l2; j<=r; ++j) ans=max(ans, q[j].h*(i-q[j].pos+1));
// cout<<"q2: "; for (int j=l2; j<=r2; ++j) cout<<q2[j].h<<','<<q2[j].pos<<' '; cout<<endl;
// cout<<"newk: "<<calc(q2[l2].h, q2[l2].pos, q2[l2+1].h, q2[l2+1].pos)<<endl;
printf("%lld ", ans);
}
printf("\n");
}
}
namespace task{
int tl[N<<2], tr[N<<2], dat[N<<2], tot;
#define tl(p) tl[p]
#define tr(p) tr[p]
#define dat(p) dat[p]
#define lin(p) lin[p]
struct line{
ll k, b;
inline ll y(ll x) {return k*x+b;}
inline void build(ll x, ll y) {k=x; b=y;}
}lin[N];
struct que{ll h, pos; inline void build(ll a, ll b) {h=a; pos=b;}}q[N];
void build(int p, int l, int r) {
tl(p)=l; tr(p)=r;
if (l==r) return ;
int mid=(l+r)>>1;
build(p<<1, l, mid);
build(p<<1|1, mid+1, r);
}
void upd(int p, int l, int r, int u) {
// if (u==3) cout<<"upd: "<<p<<' '<<l<<' '<<r<<' '<<tl(p)<<' '<<tr(p)<<' '<<u<<endl;
int v=dat(p), mid=(tl(p)+tr(p))>>1;
ll resu=lin(u).y(mid), resv=lin(v).y(mid);
// if (u==3) cout<<"res: "<<resu<<' '<<resv<<endl;
if (l<=tl(p) && r>=tr(p)) {
if (tl(p)==tr(p)) {
dat(p)=resu>resv?u:v;
return ;
}
if (lin[u].k>lin[v].k) {
if (resu>resv) {
dat(p)=u;
// cout<<"dat: "<<p<<' '<<u<<endl;
upd(p<<1, l, r, v);
}
else upd(p<<1|1, l, r, u);
}
else if (lin[u].k<lin[v].k) {
if (resu>resv) {
dat(p)=u;
upd(p<<1|1, l, r, v);
}
else upd(p<<1, l, r, u);
}
else dat(p)=resu>resv?u:v;
return ;
}
if (l<=mid) upd(p<<1, l, r, u);
if (r>mid) upd(p<<1|1, l, r, u);
}
ll query(int p, int pos) {
if (tl(p)==tr(p)) return lin[dat(p)].y(pos);
int mid=(tl(p)+tr(p))>>1;
if (pos<=mid) return max(lin[dat(p)].y(pos), query(p<<1, pos));
else return max(lin[dat(p)].y(pos), query(p<<1|1, pos));
}
void solve() {
int l=1, r=0, tem;
ll ans=0;
build(1, 1, n);
for (int i=1; i<=n; ++i) {
// cout<<"i: "<<i<<endl;
ll tem=i, h=read();
while (l<=r && q[r].h>=h) {
tem=q[r].pos;
lin[++tot].build(q[r].h, q[r].h*(1-q[r].pos));
upd(1, q[r].pos, i-1, tot);
// cout<<"pop "<<q[r].pos<<' '<<i-1<<' '<<lin[tot].k<<' '<<lin[tot].b<<endl;
--r;
}
q[++r].build(h, tem);
}
while (l<=r) {
tem=q[r].pos;
lin[++tot].build(q[r].h, q[r].h*(1-q[r].pos));
upd(1, q[r].pos, n, tot);
// cout<<"add: "<<q[r].pos<<' '<<tot<<' '<<lin[tot].k<<' '<<lin[tot].b<<' '<<lin[tot].y(n)<<endl;
--r;
}
// cout<<"dat3: "<<dat(3)<<endl;
for (int i=1; i<=n; ++i) {
ans=max(ans, query(1, i));
printf("%lld ", ans);
}
printf("\n");
}
}
signed main()
{
freopen("b.in", "r", stdin);
freopen("b.out", "w", stdout);
n=read();
// if (n<=3000) force::solve();
// else task1::solve();
task::solve();
return 0;
}