题解 擒敌拳

传送门

单调栈+斜率优化可以有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;
}
posted @ 2021-09-22 20:11  Administrator-09  阅读(8)  评论(0编辑  收藏  举报