「ROI 2018 Day 1」Innophone (分块+斜率优化)

「ROI 2018 Day 1」Innophone (分块+斜率优化)

首先可以想到对于\(x_i\)排序,枚举\(a\)为某一个\(x_i\),那么可以将余下的部分分给\(b\)计算贡献

如果将\(y_i\)倒序排成\(A_i,i\in [1,k]\),那么枚举\(b\)为某一个\(A_i\)时的贡献就是\(i\cdot A_i\)

同时要维护一个插入\(A_i\)的操作,可以固定\(A_i\),维护一个后缀个数加一的操作

\(i\cdot A_i\),同时维护\(i\rightarrow i+1\)容易让人联想到斜率优化,而区间修改的斜率优化常见的可以用分块来维护

具体的,可以分为两个操作来维护:

1.下传所有\(tag\),同时块内建立凸包

2.块内权值\(+1\),同时在凸包上完成查询,打上tag

由于随着下标,权值存在单调性,所以构建凸包应该是比较简单的

同时查询时的斜率为整个块标记的值,查询有单调性,可以直接移动队列头完成

因此维护斜率优化是线性完成的,总复杂度为\(O(n\sqrt n)\)

#include<bits/stdc++.h>
using namespace std;

typedef double db;
typedef long double ldb;
typedef long long ll;
typedef unsigned long long ull;
typedef pair <int,int> Pii;
#define reg register
#define pb push_back
#define mp make_pair
#define Mod1(x) ((x>=P)&&(x-=P))
#define Mod2(x) ((x<0)&&(x+=P))
#define rep(i,a,b) for(reg int i=a,i##end=b;i<=i##end;++i)
#define drep(i,a,b) for(reg int i=a,i##end=b;i>=i##end;--i)
template <class T> inline void cmin(T &a,const T &b){ ((a>b)&&(a=b)); }
template <class T> inline void cmax(T &a,const T &b){ ((a<b)&&(a=b)); }

char IO;
template <class T=int> T rd(){
	T s=0; int f=0;
	while(!isdigit(IO=getchar())) if(IO=='-') f=1;
	do s=(s<<1)+(s<<3)+(IO^'0');
	while(isdigit(IO=getchar()));
	return f?-s:s;
}

const int N=2e5+10,SN=600;

int n,len;
Pii A[N];
int h[N],hc;

int s[N];
struct Node{
	int l,r,tag;
	int Q[SN],L,R;
	ll Val(int x) {
		return 1ll*h[x]*(s[x]+tag);
	}
	ll Init() {
         // 重新构建凸包
      	//插入是静态的,查询是单调的,可以线性维护
		ll ans=0;
		rep(i,l,r) cmax(ans,1ll*(s[i]+=tag)*h[i]);
		tag=0,L=1,R=0;
		drep(i,r,l) {
			while(L<R && (Val(Q[R])-Val(Q[R-1]))*(h[i]-h[Q[R]]) <= (Val(i)-Val(Q[R]))*(h[Q[R]]-h[Q[R-1]])) R--;
			Q[++R]=i;
		}
		return ans;
	}
	ll Add(){
         
		tag++;
		while(L<R && Val(Q[L+1])>=Val(Q[L])) L++;
		return Val(Q[L]);
	}
} S[SN];

ll ans,Ans;
void Add(int x) { // 向A_i中插入x,维护后缀+1操作
	int p=x/len;
	rep(i,x,min(hc,(p+1)*len-1)) s[i]++;
	cmax(ans,S[p].Init());
	rep(i,p+1,hc/len) cmax(ans,S[i].Add());
}

int main(){
	n=rd();
	rep(i,1,n) A[i].first=rd(),A[i].second=rd();
	sort(A+1,A+n+1);
	rep(i,1,n) h[++hc]=A[i].second;
	sort(h+1,h+hc+1,greater<int>()),hc=unique(h+1,h+hc+1)-h-1;
	rep(i,1,n) A[i].second=lower_bound(h+1,h+hc+1,A[i].second,greater<int>())-h;
	len=sqrt(hc);
	rep(i,0,hc/len) S[i].l=max(1,i*len),S[i].r=min(hc,(i+1)*len-1),S[i].Init();

	rep(i,1,n+1) {
		cmax(Ans,1ll*(n-i+1)*A[i].first+ans);
		if(i<=n) Add(A[i].second);
	}
	printf("%lld\n",Ans);
}
posted @ 2021-02-09 23:47  chasedeath  阅读(303)  评论(0编辑  收藏  举报