HDU–6447–YJJ’s Salesman (dp+线段树)

版权声明:本文为原创文章,转载请标明出处。 https://blog.csdn.net/qq_37171272/article/details/82078016

题目链接

题意:从(0,0)点走到(1e9,1e9)这个点,每次可以由(x,y)走到(x,y+1),(x+1,y),(x+1,y+1)这三个点之一,一个点由(x,y)由价值v,如果是由(x-1,y-1)走到(x,y),那么可以获得这个价值。问走到最后能获得的最大价值是多少。

思路:倒着考虑,把点的坐标按x从小到大,y从小到大排序,容易想到ans[x][u]=max(ans[x][y+1],ans[x+1][y],v+ans[x+1][y+1]),倒着把点扫一遍,每次需要查询点(x,y)右上方最大的值,这个用线段树维护一下就好。记录当前点的最大值,当这一列的值都算完之后,把答案更新到线段树中,线段树是维护的是每个纵坐标对应的最大值,具体看一下代码,很容易理解。

AC代码:

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+10;

int n,mx[maxn],my[maxn];///行最大值和列最大值
struct P
{
    int x,y,v;
    bool operator < (const P& a)const{
        if(x==a.x) return y<a.y;
        return x<a.x;
    }
}p[maxn];
vector<int> vx,vy,v;
int getx(int x){ return lower_bound(vx.begin(),vx.end(),x)-vx.begin()+1; }
int gety(int x){ return lower_bound(vy.begin(),vy.end(),x)-vy.begin()+1; }

#define ls rt<<1
#define rs rt<<1|1
#define ll t[rt].l
#define rr t[rt].r
struct node
{
    int l,r,mx;
}t[maxn*4];
void build(int rt,int l,int r)
{
    t[rt].l=l;
    t[rt].r=r;
    t[rt].mx=0;
    if(l==r) return ;
    int mid=(l+r)>>1;
    build(ls,l,mid);
    build(rs,mid+1,r);
}
void pushup(int rt)
{
    t[rt].mx=max(t[ls].mx,t[rs].mx);
}
void update(int rt,int pos,int val)
{
    if(ll==rr){
        t[rt].mx=val;
        return ;
    }
    int mid=(ll+rr)>>1;
    if(pos<=mid) update(ls,pos,val);
    else update(rs,pos,val);
    pushup(rt);
}
int query(int rt,int l,int r)
{
    if(l>r) return 0;
    if(l<=ll&&rr<=r) return t[rt].mx;
    int mid=(ll+rr)>>1;
    int ans=0;
    if(l<=mid) ans=query(ls,l,r);
    if(r>mid) ans=max(ans,query(rs,l,r));
    return ans;
}
int main()
{
    int T;
    scanf("%d",&T);
    while(T--){
        scanf("%d",&n);
        for(int i=1;i<=n;i++){
            scanf("%d%d%d",&p[i].x,&p[i].y,&p[i].v);
            vx.push_back(p[i].x);
            vy.push_back(p[i].y);
        }
        sort(vx.begin(),vx.end());vx.erase(unique(vx.begin(),vx.end()),vx.end());
        sort(vy.begin(),vy.end());vy.erase(unique(vy.begin(),vy.end()),vy.end());
        sort(p+1,p+1+n);
        int sz=vy.size();
        v.clear();
        memset(mx,0,sizeof(mx));
        memset(my,0,sizeof(my));
        build(1,1,sz);
        int l=n,r=n;
        for(int i=n;i>=1;i--){
            if(p[i].x<p[i+1].x){///横坐标相同的点计算完之后统一更新
                for(int j=l;j<=r;j++){
                    update(1,gety(p[j].y),v[r-j]);
                }
                v.clear();
                l=r=i;
            }
            int x=getx(p[i].x),y=gety(p[i].y);
            int tmp=query(1,y+1,sz);
            int now=p[i].v+tmp;
            mx[x]=max(mx[x],now);
            my[y]=max(my[y],now);
            v.push_back(max(max(mx[x],my[y]),now));
            l=i;
        }
        for(int j=l;j<=r;j++){
            update(1,gety(p[j].y),v[j-l]);
        }
        v.clear();
        printf("%d\n",query(1,1,sz));
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_37171272/article/details/82078016