HDU 6447(线段树)
传送门
题面:
YJJ is a salesman who has traveled through western country. YJJ is always on journey. Either is he at the destination, or on the way to destination.
One day, he is going to travel from city A to southeastern city B. Let us assume that A is (0,0)(0,0) on the rectangle map and B (109,109)(109,109). YJJ is so busy so he never turn back or go twice the same way, he will only move to east, south or southeast, which means, if YJJ is at (x,y)(x,y) now (0≤x≤109,0≤y≤109)(0≤x≤109,0≤y≤109), he will only forward to (x+1,y)(x+1,y), (x,y+1)(x,y+1) or (x+1,y+1)(x+1,y+1).
On the rectangle map from (0,0)(0,0) to (109,109)(109,109), there are several villages scattering on the map. Villagers will do business deals with salesmen from northwestern, but not northern or western. In mathematical language, this means when there is a village kk on (xk,yk)(xk,yk) (1≤xk≤109,1≤yk≤109)(1≤xk≤109,1≤yk≤109), only the one who was from (xk−1,yk−1)(xk−1,yk−1) to (xk,yk)(xk,yk) will be able to earn vkvk dollars.(YJJ may get different number of dollars from different village.)
YJJ has no time to plan the path, can you help him to find maximum of dollars YJJ can get.
Input
The first line of the input contains an integer TT (1≤T≤10)(1≤T≤10),which is the number of test cases.
In each case, the first line of the input contains an integer NN (1≤N≤105)(1≤N≤105).The following NN lines, the kk-th line contains 3 integers, xk,yk,vkxk,yk,vk (0≤vk≤103)(0≤vk≤103), which indicate that there is a village on (xk,yk)(xk,yk) and he can get vkvk dollars in that village.
The positions of each village is distinct.
Output
The maximum of dollars YJJ can get.
Sample Input
1 3 1 1 1 1 2 2 3 3 1
Sample Output
3
题意:
你最开始在(0,0)点,你要走到(1e9,1e9)点。而在这个矩形范围中,一共有n个村庄(xi,yi,ki)。你每次可以走到(x+1,y),(x,y+1),(x+1,y+1)。而对于每一个村庄(a,b)而言,如果你是从(a-1,b-1)处走到(a,b)的,则你可以获得K元钱。问你从(0,0)走到(1e9,1e9)最多能够获得多少钱。
题目分析:
这个问题首先可以从dp的角度去思考。我们设为位于点(i,j)时能获得的最大的钱,则不难得出该点的状态由左边坐标,下边坐标以及左下坐标转移过来,即:
但是直接用dp去搞显然在时间和空间上都不满足题意,因此我们需要再继续分析。
根据状态转移方程,我们不难发现,处于(i,j)点的状态是由(0,0)到(i-1,j)和(0,0)到(i,j-1)的最大值转移过来的。因为存在两维状态,故我们可以考虑固定x轴,将原坐标按x轴为第一关键字从小到大排序,y轴作为第二关键字从大到小排序,进而对y轴坐标进行离散化。则此时,(i,j)的状态即由0到j-1的最大值max1转移过来,因此我们只需要维护y轴区间上的最大值即可。而对于每一个点,再获取max1后,我们还需要将该点j的最大值更新为max1+,进而不断对每个村庄进行上诉维护。最后整个y轴的最大值即为我们所需要获得的答案。
代码:
#include <bits/stdc++.h>
#define maxn 100005
using namespace std;
struct ST{
int maxx;
}tr[maxn<<2];
vector<int> Y;
struct village{
int x,y,v;
bool operator<(const village &b)const{
if(x==b.x) return y>b.y;
else return x<b.x;
}
}q[maxn];
void push_up(int rt){
tr[rt].maxx=max(tr[rt<<1].maxx,tr[rt<<1|1].maxx);
}
void update(int l,int r,int rt,int pos,int val){//区间维护最大值
if(l==r){
tr[rt].maxx=val;
return;
}
int mid=(l+r)>>1;
if(pos<=mid) update(l,mid,rt<<1,pos,val);
else update(mid+1,r,rt<<1|1,pos,val);
push_up(rt);
}
void build(int l,int r,int rt){
if(l==r){
tr[rt].maxx=0;
return;
}
int mid=(l+r)>>1;
build(l,mid,rt<<1);
build(mid+1,r,rt<<1|1);
push_up(rt);
}
int query(int L,int R,int l,int r,int rt){//区间求和
if(L<=l&&R>=r){
return tr[rt].maxx;
}
int mid=(l+r)>>1;
int ans=0;
if(L<=mid) ans=max(ans,query(L,R,l,mid,rt<<1));
if(R>mid) ans=max(ans,query(L,R,mid+1,r,rt<<1|1));
return ans;
}
int main()
{
int t;
scanf("%d",&t);
while(t--){
int n;
scanf("%d",&n);
Y.clear();
for(int i=1;i<=n;i++){
scanf("%d%d%d",&q[i].x,&q[i].y,&q[i].v);
Y.push_back(q[i].y);
}
sort(Y.begin(),Y.end());
sort(q+1,q+1+n);
Y.erase(unique(Y.begin(),Y.end()),Y.end());//离散化
int siz=Y.size();
build(0,siz,1);
for(int i=1;i<=n;i++){
int yy=lower_bound(Y.begin(),Y.end(),q[i].y)-Y.begin();
//注意此处根据离散化获得的坐标id已经为y-1,故更新的时候需要更新id+1的位置的点
int maxx=query(0,yy,0,siz,1)+q[i].v;//获取0到
update(0,siz,1,yy+1,maxx);
}
int res=query(0,siz,0,siz,1);
printf("%d\n",res);
}
return 0;
}