1. 程式人生 > 實用技巧 >題解 P6007 【[USACO20JAN]Springboards G】

題解 P6007 【[USACO20JAN]Springboards G】

本題解僅用與作者加深演算法理解,也歡迎大家的閱讀

做題背景

原本關於二維的點的 \(dp\) 問題一直都沒有什麼想法,昨天晚上再做一道 \(cdq\) 的題目的時候被同學詢問了這道題,發現可以用二維偏序使用的第一關鍵字排序,第二關鍵字用資料結構維護的方法來做,今天就把他切了。

題意

你需要從點 \((0,0)\) 走到點 \((n,n)\) ,且只能向右或向上走。同時給你 \(p\) 個點對 \((x_1,y_1),(x_2,y_2)\) ,滿足 \(x_1 \leq x_2\)\(y_1 \leq y_2\) 。如果你在中間走到了一個點對的第一個點,你可以立即達到第二點(不計算距離),問你行走的最小距離是多少。

題解

我們聯想到用解決二維偏序的方法來做。

我們先根據點對的 \(x_1\) (第一關鍵詞)和 \(y_1\) (第二關鍵詞)來排序,這樣的話我們的 \(dp\) 肯定是沒有後效性的,然後易得,每一個點對的答案肯定得是從 \(x_1\) 前面的 \(y_2\) 比它小的點轉移過來的,同時每個點可以更新的點是滿足 \(x_2\) 後面的 \(y_1\) 比他大的點,這個東西是可以用樹狀陣列來維護的。

\(P.S.\)\(y_1\) 作為第二關鍵詞是因為會出現一些比較奇怪的點對,比如點對 \((0,0),(0,1)\) 和點對 \((0,2),(0,3)\) ,此時僅根據 \(x_1\) 排序肯定是不行的,可以再加一個第二關鍵詞 \(y_1\)

然後我們又發現,每一個點更新的順序並不等於我們排序後的順序(排序是根據 \(x_1\) ,更新是根據 \(x_2\) ),所以我們可以考慮用一個 \(set\) 來維護一下更新的時間順序,到了相應的 \(x\) 軸位置再更新相應的點。

然後細節處理好就可以 \(AC\) 了,不要忘記離散化。

以上。

程式碼如下:

#include<bits/stdc++.h>
using namespace std;
#define int long long
#define IT set<pair<int,int> >::iterator
const int N=1e5+5;
int n,maxn;
struct Board{int x1,y1,x2,y2,data;}s[N];
bool cmp(Board a,Board b)
{
	if(a.x1!=b.x1)
	return a.x1<b.x1;
	return a.y1<b.y2;
};
map<int,int> mpx,mpy;
int ux[N<<1],sizex,uy[N<<1],sizey;
set<pair<int,int> > st;
struct TreeArray
{
	int s[N<<1];
	int lowbit(int x){return x&(-x);}
	void updata(int k,int x){for(;k<(N<<1);k+=lowbit(k))s[k]=min(s[k],x);}
	int query(int k){int res=1e18+7;for(;k;k-=lowbit(k))res=min(res,s[k]);return res;}
}t;
signed main()
{
	cin>>maxn>>n;;
	for(int i=1;i<=n;++i)
	{
		scanf("%lld%lld%lld%lld",&s[i].x1,&s[i].y1,&s[i].x2,&s[i].y2);
		ux[++sizex]=s[i].x1,ux[++sizex]=s[i].x2;
		uy[++sizey]=s[i].y1,uy[++sizey]=s[i].y2;
	}
	sort(s+1,s+1+n,cmp);
	ux[++sizex]=0,ux[++sizex]=maxn;
	uy[++sizey]=0,uy[++sizey]=maxn;
	sort(ux+1,ux+1+sizex);
	sort(uy+1,uy+1+sizey);
	sizex=unique(ux+1,ux+1+sizex)-ux-1;
	sizey=unique(uy+1,uy+1+sizey)-uy-1;
	for(int i=1;i<=sizex;++i) mpx[ux[i]]=i;
	for(int i=1;i<=sizey;++i) mpy[uy[i]]=i;
	for(int i=1;i<=n;++i)
	{
		int tmp=mpx[s[i].x1];
		for(IT j=st.begin();j!=st.end()&&j->first<=tmp;++j)
		t.updata(mpy[s[j->second].y2],s[j->second].data-s[j->second].x2-s[j->second].y2);
		while(!st.empty()&&st.begin()->first<=tmp) st.erase(st.begin());
		s[i].data=t.query(mpy[s[i].y1])+s[i].x1+s[i].y1;
		st.insert(make_pair(mpx[s[i].x2],i));
		// printf("%d %d %d\n",s[i].x1,s[i].y1,s[i].data);
	}
	int tmp=mpx[maxn];
	for(IT j=st.begin();j!=st.end()&&j->first<=tmp;++j)
	t.updata(mpy[s[j->second].y2],s[j->second].data-s[j->second].x2-s[j->second].y2);
	printf("%lld\n",t.query(mpy[maxn])+maxn+maxn);
	return 0;
}