【USACO19FEB】Mowing Mischief P(决策单调性)(线段树辅助分治)

传送门


题解:

容易想到首先要求一个LIS。

根据以其结尾的LIS长度,把点分为若干集合,设为 SlS_l,容易注意到一个集合中横座标增加的同时纵座标减小。

容易得到一个显然的DP:dpi=minjSl1xj<xi,yj<yidpj+(xixj)(yiyj)dp_i=\min_{j\in S_{l-1}x_j<x_i,y_j<y_i}dp_j+(x_i-x_j)*(y_i-y_j)

发现权值的图像好像是反比例函数,考虑什么时候决策 jj 比决策 kk 优秀。

dpj+(xixj)(yiyj)dpk+(xixk)(yiyk)xi(ykyi)+yi(xkxj)dpkdpj+xkykxjyjdp_j+(x_i-x_j)(y_i-y_j)\leq dp_k+(x_i-x_k)(y_i-y_k)\\ x_i(y_k-y_i)+y_i(x_k-x_j)\leq dp_k-dp_j+x_ky_k-x_jy_j\\

发现决策的分界线是一条斜率为正的直线,一个半平面会选择 jj 另一个会选择 kk

但是我们显然是不能把所有半平面算出来求半平面交的。

但是我们知道如果对于某个点决策 jj 比决策 kk 优秀,则这个点左边/右边的所有点决策 jj 都比决策 kk 优秀。

于是可以分治下去找到最优决策,注意DP对座标有要求,结合线段树进行分治即可。

分治套分治,复杂度两个log。


代码:

#include<bits/stdc++.h>
#define ll long long
#define re register
#define cs const

namespace IO{

inline char gc(){
	static cs int Rlen=1<<22|1;static char buf[Rlen],*p1,*p2;
	return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,Rlen,stdin),p1==p2)?EOF:*p1++;
}template<typename T>T get_integer(){
	char c;bool f=false;while(!isdigit(c=gc()))f=c=='-';T x=c^48;
	while(isdigit(c=gc()))x=((x+(x<<2))<<1)+(c^48);return f?-x:x;
}inline int gi(){return get_integer<int>();}

}using namespace IO;

using std::cerr;
using std::cout;

cs int N=2e5+7;

int n,T;
int x[N],y[N],id[N];
int lis[N],a[N],mx;

ll calc(int i,int j){
	return (ll)(x[i]-x[j])*(y[i]-y[j]);
}

std::vector<int> ps[N];
ll dp[N];

namespace SGT{

std::vector<int> sol[N<<2];

#define lc u<<1
#define rc lc|1

void DP(int ql,int qr,cs std::vector<int> &q,int l,int r,cs std::vector<int> &ps){
	int qm=(ql+qr)>>1,qid=q[qm],m=0;ll tmp=1e18;
	for(int re i=l;i<=r;++i)
		if(tmp>dp[ps[i]]+calc(ps[i],qid))
			{tmp=dp[ps[i]]+calc(ps[i],qid),m=i;}
	dp[qid]=std::min(dp[qid],tmp);
	if(ql<qm)DP(ql,qm-1,q,m,r,ps);
	if(qm<qr)DP(qm+1,qr,q,l,m,ps);
}

void ins(int u,int l,int r,int p,cs std::vector<int> &ps){
	if(y[ps[l]]<y[p]&&x[ps[r]]<x[p])
		return sol[u].push_back(p);
	if(y[ps[r]]>y[p]||x[ps[l]]>x[p])
		return ;int m=(l+r)>>1;
	ins(lc,l,m,p,ps);ins(rc,m+1,r,p,ps);
}
void solve(int u,int l,int r,cs std::vector<int> &ps){
	if(sol[u].size())DP(0,sol[u].size()-1,sol[u],l,r,ps);
	sol[u].clear();if(l==r)return ;int m=(l+r)>>1;
	solve(lc,l,m,ps);solve(rc,m+1,r,ps);
}

}

void Main(){
	n=gi(),T=gi();
	for(int re i=1;i<=n;++i)
		x[i]=gi(),y[i]=gi(),id[i]=i;
	std::sort(id+1,id+n+1,
		[](int i,int j){return x[i]<x[j];});mx=0;
	for(int re i=1;i<=n;++i){
		int j=id[i];
		if(y[j]>=a[mx]){
			lis[j]=++mx;
			a[mx]=y[j];
		}else {
			lis[j]=std::upper_bound(a+1,a+mx+1,y[j])-a;
			a[lis[j]]=y[j];
		}ps[lis[j]].push_back(j);
	}std::fill(dp+1,dp+n+1,1e18);
	for(int i:ps[1])dp[i]=(ll)x[i]*y[i];
	for(int re i=2;i<=mx;++i){
		for(int j:ps[i])
			SGT::ins(1,0,ps[i-1].size()-1,j,ps[i-1]);
		SGT::solve(1,0,ps[i-1].size()-1,ps[i-1]);
	}ll ans=1e18;
	for(int i:ps[mx])
		ans=std::min(ans,dp[i]+(ll)(T-x[i])*(T-y[i]));
	cout<<ans<<"\n";
}

inline void file(){
#ifdef zxyoi
	freopen("mischief.in","r",stdin);
#endif
}signed main(){file();Main();return 0;}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章