题解 矩形

传送门

首先可以二分出第 \(i\) 个数是什么
于是可以通过 \(R-L+1 \leqslant 3\) 的部分分
然后到这里其实就可以知道第 \(L\) 个数是什么以及有多少了,难点在于不好知道下一个数是什么
于是题解说它是个经典问题
首先可以知道每个 \(h\) 在什么范围内是最小值
然后每个 \(h\) 对可能的值域的贡献就是这个 \(h\) 的倍数
于是可以参考这题
不过不需要队列实现,记一下现在到了这个 \(h\) 的几倍就好了
具体的,用小根堆维护 \((l, r, p, w)\) 表示 \(h_p\) 的管辖范围是 \([l, r]\),此时考虑到了 \(h_p\) 的第 \(w\)
特别注意一点,因为是堆实现,所以如果一个四元组一个在 \(w\) 时已经不合法了,就要直接将其删除
若将 \(w+1\) 的情况也放到堆里复杂度就假了(因为它可能被取出若干次却无法对合法方案产生贡献)

Code:
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define N 300010
#define ll long long
#define int128 __int128
#define fir first
#define sec second
#define make make_pair
// #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 ll read() {
	ll 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;
}
char sta[N]; int top;
void write(int128 t) {
	top=0;
	do {sta[++top]='0'+t%10; t/=10;} while (t);
	while (top) putchar(sta[top--]);
	putchar(' ');
}

int n;
ll h[N], l, r, ql, qr;

namespace force{
	int top;
	ll a[1000010];
	void solve() {
		for (int i=1; i<=n; ++i) {
			ll minn=h[i];
			for (int j=i; j<=n; ++j) {
				minn=min(minn, h[j]);
				a[++top]=minn*(j-i+1);
			}
		}
		sort(a+1, a+top+1);
		for (int i=l; i<=r; ++i) printf("%lld%c", a[i], " \n"[i==top]);
		exit(0);
	}
}

namespace task1{
	ll buc[N];
	void solve() {
		int len=r-l+1;
		for (int i=1; i<=n; ++i) buc[i]=n-i+1;
		int now=1; --l;
		while (1) {
			if (buc[now]>=l) {
				buc[now]-=l;
				if (!buc[now]) ++now;
				break;
			}
			l-=buc[now];
			++now;
		}
		for (int i=1; i<=len; ++i) {
			while (!buc[now]) ++now;
			--buc[now];
			printf("%d%c", now, " \n"[i==len]);
		}
		exit(0);
	}
}

namespace task{
	int ls[N], rs[N], lg[N], rg[N], top;
	pair<int, int> sta[N];
	struct tpl{
		ll l, r, p, w, h, s;
		tpl(){}
		tpl(ll a, ll b, ll c, ll d, ll e):l(a),r(b),p(c),w(d),h(e){s=w*h;}
	}tp[N];
	inline bool operator < (tpl a, tpl b) {return a.s>b.s;}
	struct cmp{inline bool operator () (int a, int b) {return tp[a]<tp[b];}};
	priority_queue<int, vector<int>, cmp> q;
	void dfs(int u) {
		lg[u]=rg[u]=u;
		if (ls[u]) dfs(ls[u]), lg[u]=min(lg[u], lg[ls[u]]);
		if (rs[u]) dfs(rs[u]), rg[u]=max(rg[u], rg[rs[u]]);
	}
	int128 S(int128 w) {return w<=0?0:w*(w+1)/2;}
	ll T(ll a, ll b) {return a<b?0:a-b+1;}
	ll check(ll s) {
		// cout<<"check: "<<s<<endl;
		ll ans=0;
		for (int i=1; i<=n; ++i) {
			ll w=(s-1)/h[i];
			int l1=i-lg[i]+1, l2=rg[i]-i+1;
			ans+=S(w)-S(w-l1)-S(w-l2)+S(w-l1-l2);
		}
		// cout<<"ans: "<<ans<<endl;
		return ans;
	}
	void solve() {
		for (int i=1; i<=n; ++i) {
			int k=top;
			while (k && sta[k].sec>h[i]) --k;
			if (k) rs[sta[k].fir]=i;
			if (k<top) ls[i]=sta[k+1].fir;
			sta[++k]=make(i, h[i]);
			top=k;
		}
		// cout<<1<<endl;
		dfs(sta[1].fir);
		// cout<<2<<endl;
		ll l=1, r=1e15, mid;
		while (l<=r) {
			mid=(l+r)>>1;
			if (check(mid)<ql) l=mid+1;
			else r=mid-1;
		}
		int tot=qr-ql+1; ll tem=check(l)-ql+1;
		for (int i=1; i<=min(tem, 1ll*tot); ++i) printf("%lld ", l-1);
		tot-=tem;
		for (int i=1; i<=n; ++i) {
			ll w=(l-1)/h[i]+1;
			tp[i]=tpl(lg[i], rg[i], i, w, h[i]);
			q.push(i);
		}
		while (tot>0) {
			// cout<<"tot: "<<tot<<endl;
			int t=q.top(); q.pop();
			int cnt=T(tp[t].r-tp[t].l+1, tp[t].w)-T(tp[t].p-tp[t].l, tp[t].w)-T(tp[t].r-tp[t].p, tp[t].w);
			if (cnt<=0) continue;
			ll tem=tp[t].w*tp[t].h;
			if (cnt>=tot) for (int i=1; i<=tot; ++i) printf("%lld ", tem);
			else for (int i=1; i<=cnt; ++i) printf("%lld ", tem);
			tot-=cnt;
			++tp[t].w; tp[t].s=tp[t].w*tp[t].h;
			q.push(t);
		}
		printf("\n");
	}
}

signed main()
{
	freopen("rectangle.in", "r", stdin);
	freopen("rectangle.out", "w", stdout);

	n=read();
	bool all_one=1;
	for (int i=1; i<=n; ++i) {
		h[i]=read();
		if (h[i]!=1) all_one=0;
	}
	ql=l=read(); qr=r=read();
	// if (all_one) task1::solve();
	// else force::solve();
	task::solve();

	return 0;
}
posted @ 2021-10-25 09:52  Administrator-09  阅读(0)  评论(0编辑  收藏  举报