2018中國大學生程序設計競賽 - 網絡選拔賽--HDU 6447 YJJ's Salesman(dp+線段樹)

題意:

一個人要從(0,0)的村莊走到(1e9,1e9)的村莊,有些村莊有 w 值。他只能斜着走才能獲得那些值,問你他最多可以獲得多少值。

題解:

如題我們可以得到 dp 公式 :dp[i][j] = max(dp[i-1][j-1]+w, dp[i-1][j], dp[i][j-1], w)。

但是我們直接離散化後去跑整個圖是不行的,因爲圖太大了。其實我們可以發現 dp[i][j] = max(dp[i-1][j-1]+w, max(dp[0][j]......dp[i-1][j]), max(dp[i][0]......dp[i][j-1]), w),這樣我們如果可以快速找到第 i 行 0 ... j-1中最大值,去更新就會快很多不用每個都更新,用線段樹去查詢最大值。我們還可以優化二維數組,我們可以像一維揹包一樣把 dp[i][j] 看做 tree[j],i 從小往大更新即可。

更新公式就變爲 :tree[j] = max(tree[j],tree[0]...tree[j-1]+w),tree[j]在維護的過程中就是第 j 列的最大值不用去找。

#include <algorithm>
#include  <iostream>
#include   <cstdlib>
#include   <cstring>
#include    <cstdio>
#include    <string>
#include    <vector>
#include    <bitset>
#include     <stack>
#include     <cmath>
#include     <deque>
#include     <queue>
#include      <list>
#include       <set>
#include       <map>
#define mem(a, b) memset(a, b, sizeof(a))
#define inf 0x7ffffff
#define pi acos(-1)
using namespace std;
typedef long long ll;

const int maxn = 1e5+10;
int tree[maxn << 2], disperse_x[maxn], disperse_y[maxn];

struct node{
	int x, y, w;
}point[maxn];

int cmp(node a, node b){
	if(a.x == b.x){
		return a.y > b.y;
	}
	return a.x < b.x;
}

void build(int root, int l, int r){
	if(l == r){
		tree[root] = 0;
		return;
	}
	int mid = (l + r) >> 1;
	build(root << 1, l, mid);
	build(root << 1 | 1, mid+1, r);
	tree[root] = max(tree[root << 1], tree[root << 1 | 1]);
}

int query(int root, int l, int r, int ql, int qr){
	if(l == ql && r == qr){
		return tree[root];
	}
	int mid = (l + r) >> 1; 
	if(mid >= qr){
		return query(root << 1, l, mid, ql, qr);
	}
	else if(mid < ql){
		query(root << 1 | 1, mid+1, r, ql, qr);
	}
	else{
		return max(query(root << 1, l, mid, ql, mid), query(root << 1 | 1, mid+1, r, mid+1, qr));
	}
}

void update(int root, int id, int num, int l, int r){
	if(l == r && l == id){
		tree[root] = max(tree[root], num);
		return;
	}
	int mid = (l + r) >> 1; 
	if(mid >= id){
		update(root << 1, id, num, l, mid);
	}
	else{
		update(root << 1 | 1, id, num, mid+1, r);
	}
	tree[root] = max(tree[root << 1], tree[root << 1 | 1]);
}

int main(){
	int t;
	scanf("%d", &t);
	while(t--){
		int n;
		scanf("%d", &n);
		for(int i = 0; i < n; i++){
			scanf("%d %d %d", &point[i].x, &point[i].y, &point[i].w);
			disperse_x[i] = point[i].x;
			disperse_y[i] = point[i].y;
		}
		sort(disperse_x, disperse_x+n);
		sort(disperse_y, disperse_y+n);
		int len1 = unique(disperse_x, disperse_x+n) - disperse_x;
		int len2 = unique(disperse_y, disperse_y+n) - disperse_y;
		for(int i = 0; i < n; i++){
			point[i].x = lower_bound(disperse_x, disperse_x+len1, point[i].x) - disperse_x;
			point[i].y = lower_bound(disperse_y, disperse_y+len2, point[i].y) - disperse_y;
		}
		sort(point, point+n, cmp);
		build(1, 0, n);
		int ans = 0;
		for(int i = 0; i < n; i++){
			int maxx = point[i].y == 0 ? point[i].w : query(1, 0, n, 0, point[i].y-1) + point[i].w;
			update(1, point[i].y, maxx, 0, n);
			ans = max(ans, maxx);
		}
		printf("%d\n", ans);
	}
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章