题解 序列

传送门

发现那个 \(k\) 每次都在变着实很烦
于是将 \(k\) 看做变量 \(x\),将 \(\sum b\) 看做 \(k\),将 \(\sum a\) 看做 \(b\)
于是每个决策点都可以表示为一条 \(kx+b\) 的直线,李超树维护即可

  • 李超树维护直线(不是线段)是 \(O(nlogn)\)
Code:
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f3f3f3f3f
#define N 1000010
#define ll long long
#define fir first
#define sec second
#define make make_pair
#define pb push_back
//#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, m;
ll a[N], b[N];

#if 0
namespace force{
	ll calc(int l, int r, ll k) {
		ll suma=0, sumb=0;
		for (int i=l; i<=r; ++i) suma+=a[i], sumb+=b[i];
		return suma-k*sumb;
	}
	void solve() {
		ll k, ans;
		for (int i=1,p; i<=m; ++i) {
			p=read(); k=read(); ans=-INF;
			for (int l=1; l<=p; ++l) for (int r=p; r<=n; ++r) ans=max(ans, calc(l, r, k));
			printf("%lld\n", ans);
		}
		exit(0);
	}
}

namespace task1{
	ll ans[N], prea[N], preb[N], sufa[N], sufb[N];
	vector<pair<int, int>> que[N];
	void solve() {
		for (int i=1; i<=n; ++i) prea[i]=prea[i-1]+a[i], preb[i]=preb[i-1]+b[i];
		for (int i=n; i; --i) sufa[i]=sufa[i+1]+a[i], sufb[i]=sufb[i+1]+b[i];
		for (int i=1; i<=m; ++i) {
			int p=read(), k=read();
			que[p].pb(make(k, i));
		}
		for (int i=1; i<=n; ++i) for (auto it:que[i]) {
			ll k=it.fir, tem;
			tem=-k*sufb[i]+sufa[i];
			for (int j=1; j<=i; ++j) tem=max(tem, -k*sufb[j]+sufa[j]);
			ans[it.sec]+=tem-(-k*sufb[i]+sufa[i]);
			tem=-k*preb[i]+prea[i];
			for (int j=i; j<=n; ++j) tem=max(tem, -k*preb[j]+prea[j]);
			ans[it.sec]+=tem-(-k*preb[i]+prea[i]);
			ans[it.sec]+=a[i]-k*b[i];
		}
		for (int i=1; i<=m; ++i) printf("%lld\n", ans[i]);
		exit(0);
	}
}
#endif

namespace task2{
	ll ans[N], prea[N], preb[N], sufa[N], sufb[N];
	vector<pair<int, int>> que[N];
	struct line{
		ll k, b;
		line(){}
		line(ll x, ll y):k(x),b(y){}
		inline ll at(ll x) {return k*x+b;}
	};
	struct lichao{
		line dat[N<<3];
		// int tl[N<<3], tr[N<<3];
		bool noline[N<<3];
		// bitset<N<<3> noline;
		// #define tl(p) tl[p]
		// #define tr(p) tr[p]
		#define noline(p) noline[p]
		#define dat(p) dat[p]
		void build(int p, int l, int r) {
			// cout<<"build: "<<p<<' '<<l<<' '<<r<<endl;
			// tl(p)=l; tr(p)=r;
			noline(p)=1; dat(p)=line(0, 0);
			if (l==r) return ;
			int mid=floor((l+r)/2.0L);
			build(p<<1, l, mid);
			build(p<<1|1, mid+1, r);
		}
		void upd(int p, int tl, int tr, const int& l, const int& r, line val) {
			// cout<<"upd: "<<p<<' '<<tl(p)<<' '<<tr(p)<<' '<<l<<' '<<r<<' '<<val.k<<' '<<val.b<<endl;
			int mid=floor((tl+tr)/2.0);
			if (l<=tl&&r>=tr) {
				if (noline(p)) {dat(p)=val; noline(p)=0; return ;}
				if (tl==tr) {
					if (val.at(tl)>dat(p).at(tl)) dat(p)=val;
					return ;
				}
				if (dat(p).k==val.k) dat(p)=dat(p).b>val.b?dat(p):val;
				else if (dat(p).k>val.k) {
					if (dat(p).at(mid)>=val.at(mid)) {
						// upd(p<<1, l, r, dat(p));
						upd(p<<1, tl, mid, l, r, val);
					}
					else {
						// upd(p<<1|1, l, r, val);
						upd(p<<1|1, mid+1, tr, l, r, dat(p));
						dat(p)=val;
					}
				}
				else {
					if (dat(p).at(mid)>=val.at(mid)) {
						// upd(p<<1|1, l, r, dat(p));
						upd(p<<1|1, mid+1, tr, l, r, val);
					}
					else {
						upd(p<<1, tl, mid, l, r, dat(p));
						// upd(p<<1, l, r, val);
						dat(p)=val;
					}
				}
				return ;
			}
			if (l<=mid) upd(p<<1, tl, mid, l, r, val);
			if (r>mid) upd(p<<1|1, mid+1, tr, l, r, val);
		}
		ll query(int p, int tl, int tr, const ll pos) {
			// cout<<"query: "<<p<<' '<<pos<<' '<<dat(p).k<<' '<<dat(p).b<<' '<<noline(p)<<endl;
			ll dlt=noline(p)?-INF:dat(p).at(pos);
			if (tl==tr) return dlt;
			int mid=floor((tl+tr)/2.0L);
			if (pos<=mid) return max(query(p<<1, tl, mid, pos), dlt);
			else return max(query(p<<1|1, mid+1, tr, pos), dlt);
		}
	}tr1;
	void solve() {
		// cout<<double(sizeof(tr1))/1000/1000<<endl; return ;
		ll lim=1000010;
		tr1.build(1, -lim, lim);
		for (int i=1; i<=n; ++i) prea[i]=prea[i-1]+a[i], preb[i]=preb[i-1]+b[i];
		for (int i=n; i; --i) sufa[i]=sufa[i+1]+a[i], sufb[i]=sufb[i+1]+b[i];
		for (int i=1; i<=m; ++i) {
			int p=read(), k=read();
			que[p].pb(make(k, i));
		}
		for (int i=1; i<=n; ++i) {
			// cout<<"i: "<<i<<endl;
			tr1.upd(1, -lim, lim, -lim, lim, line(sufb[i], sufa[i]));
			for (auto it:que[i]) {
				ll k=it.fir, tem=tr1.query(1, -lim, lim, -k);
				// cout<<"tem: "<<tem<<endl;
				ans[it.sec]+=tem-(-k*sufb[i]+sufa[i]);
			}
		}
		tr1.build(1, -lim, lim);
		for (int i=n; i; --i) {
			// cout<<"i: "<<i<<endl;
			tr1.upd(1, -lim, lim, -lim, lim, line(preb[i], prea[i]));
			for (auto it:que[i]) {
				ll k=it.fir, tem=tr1.query(1, -lim, lim, -k);
				// cout<<"tem: "<<tem<<endl;
				ans[it.sec]+=tem-(-k*preb[i]+prea[i]);
			}
		}
		for (int i=1; i<=n; ++i) for (auto it:que[i]) {
			ans[it.sec]+=a[i]-it.fir*b[i];
		}
		for (int i=1; i<=m; ++i) printf("%lld\n", ans[i]);
		exit(0);
	}
}

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

	n=read(); m=read();
	for (int i=1; i<=n; ++i) a[i]=read(), b[i]=read();
	// force::solve();
	// task1::solve();
	task2::solve();

	return 0;
}
posted @ 2021-11-14 19:44  Administrator-09  阅读(1)  评论(0编辑  收藏  举报