1. 程式人生 > >HDU 6447(線段樹)

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;
}