HDU-6447 YJJ's Salesman 线段树+推导(维护区间最大值)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/xiang_6/article/details/82055513

题意:

给定n个点,每个点有个权值,只有从这个点的左下方45°上来,才能获得这个点的权值,每次只能从某个点往上走一格或往右走一格,或往右上走一格,

问:找一条路径,使获得权值最大;

思路:

首先我们能够想到对于A点(x1,y1),它的最优值应该是由某个  B点(x2,y2)  &&  x2<x1  &&  y2<y1  得来的,如果遍历的话 n^2 复杂度不能接受,所以对于点A,我们要想办法快速的得到上述满足B点的最大值,

首先按照x坐标从小到大排序,这样从前往后遍历的时候,当前点前面的点的x 坐标是满足条件的(如果有x坐标相同的情况,另行处理),我们只要查找y坐标满足情况的最大值就ok了,,这样我们会想到离散化每个点的y坐标,然后按 y坐标建的线段树,维护最大值,,

为了解决上述的x坐标相同的情况,我们先把x相同的点存起来,如果后续遇到跟他不同的点,再更新线段树;

#include<iostream>
#include <cstdio>
#include<algorithm>
#include <cstring>
#include <set>
#include <bitset>
#include <map>

using namespace std;
typedef pair<int,int> P;
typedef long long ll;
const int maxn = 1e5 + 7;
const int INF = 0x3f3f3f3f;

map<int, int> mp;
struct node {
  int x;
  int y;
  int ny;
  int v;
}a[maxn];
bool cmp(node a,node b) {
  if(a.x == b.x) {
    return a.y < b.y;
  }
  return a.x < b.x;
}

int n;
int b[maxn];

void init() {
  mp.clear();

  scanf("%d", &n);
  for(int i = 1; i <= n; ++i) {
    scanf("%d%d%d", &a[i].x, &a[i].y, &a[i].v);
    b[i] = a[i].y;
  }
  sort(b+1,b+1+n);
  sort(a+1,a+1+n, cmp);
  int t = -1, id = 1;
  for(int i = 1; i <= n; ++i) {
    if(b[i] != t) {
      mp[b[i]] = id++;
      t = b[i];
    }
    else mp[b[i]] = mp[b[i-1]];
  }
  for(int i = 1; i <= n; ++i) {
    a[i].ny = mp[a[i].y];
  }
}


int max_[maxn<<2];

int query(int id, int l_, int r_, int ql, int qr) {
  if(r_ < ql || l_ > qr) return 0;
  if(ql == l_ && qr == r_) {
    return max_[id];
  }
  int mid = (l_ + r_) / 2;
  if(ql > mid) {
    return (query((id<<1)|1, mid+1, r_, ql, qr));
  }
  else if(qr <= mid) {
    return (query((id<<1), l_, mid, ql, qr));
  }
  else {
    return max((query((id<<1), l_, mid, ql, mid)),(query((id<<1)|1, mid+1, r_, mid+1, qr)));
  }
}
void push_up(int id) {
  max_[id] = max(max_[(id<<1)], max_[(id<<1)|1]);
}
void update(int id, int l_, int r_, int ul, int ur, int v) {
  if(l_ == r_ && ul == ur) {
    max_[id] = max(max_[id], v);
    return;
  }
  int mid = (l_ + r_) / 2;
  if(ul > mid) {
    update((id<<1|1),mid+1, r_, ul, ur, v);
  }
  else if(ur <= mid) {
    update((id<<1),l_, mid, ul, ur, v);
  }
  else {
    update((id<<1),l_, mid, ul, mid, v);
    update((id<<1)|1,mid+1, r_, mid+1, ur, v);
  }
  push_up(id);
}

int dp[maxn];
int main() {
  int T;
  scanf("%d", &T);
  while(T--) {
    init();
    memset(max_, 0, sizeof max_);
    memset(dp, 0, sizeof dp);
    int ans = 0, xx = -1;
    set<P> st;
    for(int i = 1; i <= n; ++i) {
      if(a[i].x != xx) {
        for(auto p : st) {
          update(1, 1, n, p.first, p.first, p.second);
        }
        st.clear();
        xx = a[i].x;
      }

      int ny = a[i].ny;
      int maxt = query(1,1,n,1,ny-1);
      dp[i] = maxt+a[i].v;
      st.insert(P(a[i].ny,dp[i]));
      ans = max(ans, dp[i]);
    }
    printf("%d\n", ans);
  }
  return 0 ;
}

猜你喜欢

转载自blog.csdn.net/xiang_6/article/details/82055513