CCPC 2018 网络赛 1010 YJJ's Salesman

http://acm.hdu.edu.cn/showproblem.php?pid=6447

YJJ's Salesman

Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 1330    Accepted Submission(s): 470


 

Problem Description

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) on the rectangle map and B (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) now (0≤x≤109,0≤y≤109) , he will only forward to (x+1,y) , (x,y+1) or (x+1,y+1) .
On the rectangle map from (0,0) to (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 k on (xk,yk) (1≤xk≤109,1≤yk≤109) , only the one who was from (xk−1,yk−1) to (xk,yk) will be able to earn vk 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 T (1≤T≤10) ,which is the number of test cases.

In each case, the first line of the input contains an integer N (1≤N≤105) .The following N lines, the k -th line contains 3 integers, xk,yk,vk (0≤vk≤103) , which indicate that there is a village on (xk,yk) and he can get vk 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

 

 

Source

2018中国大学生程序设计竞赛 - 网络选拔赛

 

 

Recommend

chendu   |   We have carefully selected several similar problems for you:  6447 6446 6445 6444 6443 

 

 

思路:DP+线段树+离散化,当初想的时候只想到了如何找出i结点之前的比这个结点y值小的的最大值如何用线段树求出,想不出来就放弃了线段树的思路。原来答案是高度1~y-1的最大值用线段树保存。真是菜鸡

 

AC代码

#include<bits/stdc++.h>
using namespace std;

#define N 100005
struct node{
    long long x=0;
    long long y=0;
    long long v=0;
};
node nodes[N];
long long maxn[N<<2];
int posHash[N];
long long maxy;

void init(int n)
{
    sort(nodes+1,nodes+1+n,[](const node a,const node b){return a.x<b.x;});
    posHash[0]=1;
    for(int i=1;i<=n;++i)
    {
        if(nodes[i].x==nodes[i-1].x)
            posHash[i]=posHash[i-1];
        else
            posHash[i]=posHash[i-1]+1;
    }
    for(int i=1;i<=n;++i)
    {
        nodes[i].x=posHash[i];
    }//x值数据离散化
    sort(nodes+1,nodes+1+n,[](const node a,const node b){return a.y<b.y;});
    posHash[0]=1;
    for(int i=1;i<=n;++i)
    {
        if(nodes[i].y==nodes[i-1].y)
            posHash[i]=posHash[i-1];
        else
            posHash[i]=posHash[i-1]+1;
    }
    for(int i=1;i<=n;++i)
        nodes[i].y=posHash[i];
    maxy=posHash[n];//y值数据离散化
}

void build(int l,int r,int rt)
{
    if(l==r)
        maxn[rt]=0;
    else
    {
        int mid=(l+r)>>1;
        build(l,mid,rt<<1);
        build(mid+1,r,rt<<1|1);
        maxn[rt]=max(maxn[rt<<1],maxn[rt<<1|1]);
    }
}

void update(int L,int C,int l,int r,int rt)
{
    if(l==r)
    {
        maxn[rt]=max(maxn[rt],(long long)C);
        return;
    }
    else
    {
        int mid=(l+r)>>1;
        if(L<=mid)
            update(L,C,l,mid,rt<<1);
        else
            update(L,C,mid+1,r,rt<<1|1);
        maxn[rt]=max(maxn[rt<<1],maxn[rt<<1|1]);
    }
}

long long query(int L,int R,int l,int r,int rt)
{
    if(L<=l&&R>=r)
    {
        return maxn[rt];
    }
    else
    {
        long long ans=0;
        int mid=(l+r)>>1;
        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()
{
    std::ios::sync_with_stdio(false);
    int t;
    cin>>t;
    while(t--)
    {
        int n;
        cin>>n;
        for(int i=1;i<=n;++i)
            cin>>nodes[i].x>>nodes[i].y>>nodes[i].v;
        init(n);
        sort(nodes+1,nodes+1+n,[](const node a,const node b){return a.x==b.x?a.y>b.y:a.x<b.x;});
        build(1,maxy,1);
        long long result=0;
        for(int i=1;i<=n;++i)
        {
            long long ans=0;
            if(nodes[i].y==1)
                ans=nodes[i].v;
            else
                ans=query(1,nodes[i].y-1,1,maxy,1)+nodes[i].v;
            result=max(result,ans);
            update(nodes[i].y,ans,1,maxy,1);
        }
        cout<<result<<endl;
    }
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值