【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;}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章