HDU 3607 线段树+DP+离散化

题意:从左往右跳箱子,每个箱子有金币数量,只能从矮处向高处跳,求最大可获得金币数,数据规模1<=n<=1e5.

显然是一个dp的问题,不难得出dp[ i ] = max(dp[j] )+val [ i ] ,j < i ; 第一眼会想到o(n^2)的算法,显然会超时,这个时候就需要用线段树维护最大值,将复杂度降低到o(nlogn)

首先离散化处理,将高度从小到大排序,并使用unique函数去重,之后每个高度就可以映射为它的下标pos,然后用线段树维护每个下标对应的最优解bestans [ pos ] ,每当向后进行新的决策时,

先找出状态转移方程中的max( dp [ j ] ) ,线段树操作是o(logn)的,然后用dp [ i ] = max( dp [ j ])+val[ i ] 更新线段树中 ( h[ i ] 对应下标pos ) bestans[ pos ] 的值

#include<bits/stdc++.h>
#define N 100050
#define debug cout<<"???"<<endl;
using namespace std;
int val[N],mx[N<<2],h[N];
void pushup(int rt)
{
    mx[rt]=max(mx[rt<<1],mx[rt<<1|1]);
}
int query(int L,int R,int l,int r,int rt)
{
    if(L>R)return 0;
    if(L<=l&&r<=R)return mx[rt];
    int m=(l+r)>>1;
    int ans=0;
    if(L<=m)ans=max(ans,query(L,R,l,m,rt<<1));
    if(R>m)ans=max(ans,query(L,R,m+1,r,rt<<1|1));
    return ans;
}
void updata(int pos,int val,int l,int r,int rt)
{
    if(l==r){
        mx[rt]=val;
        return;
    }
    int m=(l+r)>>1;
    if(pos<=m)updata(pos,val,l,m,rt<<1);
    if(pos>m)updata(pos,val,m+1,r,rt<<1|1);
    pushup(rt);
}
void init()
{
    memset(mx,0, sizeof(mx));
}
int main()
{
    int n,x;
    while(cin>>n) {
        init();
        vector<int>ve;
        for (int i = 1; i <= n; i++) {
            scanf("%d%d",&h[i],val+i);
            ve.emplace_back(h[i]);
        }
        int ans=0;
        sort(ve.begin(),ve.end());
        unique(ve.begin(),ve.end());
        for(int i=1;i<=n;i++)
        {
            int pos=int(lower_bound(ve.begin(),ve.end(),h[i])-ve.begin()+1);
            int tmp=query(1,pos-1,1,int(ve.size()),1);
            updata(pos,tmp+val[i],1,int(ve.size()),1);
            ans=max(ans,tmp+val[i]);
        }
        cout<<ans<<endl;
    }
    return 0;
}

原文地址:https://www.cnblogs.com/xusirui/p/9396145.html

时间: 2024-11-09 02:12:21

HDU 3607 线段树+DP+离散化的相关文章

hdu 4747 线段树/DP

先是线段树 可以知道mex(i,i),mex(i,i+1)到mex(i,n)是递增的. 首先很容易求得mex(1,1),mex(1,2)......mex(1,n) 因为上述n个数是递增的. 然后使用线段树维护,需要不断删除前面的数. 比如删掉第一个数a[1]. 那么在下一个a[1]出现前的 大于a[1]的mex值都要变成a[1] 因为是单调递增的,所以找到第一个 mex > a[1]的位置,到下一个a[1]出现位置,这个区间的值变成a[1]. 然后需要线段树实现区间修改和区间求和 #inclu

hdu 3564 线段树+dp(最大递增子序列)

对于数列插空问题, 常用线段树来处理,从后往前,因为后面的数的位置是不会改变的,对于i的位置  ,如果i位置上已经有数了,那么就找i之后第一个空位,num[i]=k纪录i所放的位置, 然后就按照hdu1025做法一样了    , #include<stdio.h> #include<string.h> #include<iostream> using namespace std; #define LL(x) (x<<1) #define RR(x) ((x&

hdu 4288 线段树+离线+离散化

http://acm.hdu.edu.cn/showproblem.php?pid=4288 开始的时候,果断TLE,做的方法是,线段树上仅仅维护%5==3的坐标,比如1 2 3 4 5 6 7  如果删除第三个数,就将3,6的位置全+1,就是向右偏移以为,但是求和还是很慢,所以即使10秒,还是TLE... 正确做法: 1.节点内维护sum[0...4]分别代表区间内%5==i的和 2.结点维护点的个数,cnt 3.离散化处理,然后每次插入时,经过的结点cnt+1或-1,叶子节点Sum[0]就是

HDU 1542 线段树+扫描线+离散化

Atlantis Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 8327    Accepted Submission(s): 3627 Problem Description There are several ancient Greek texts that contain descriptions of the fabled is

[HDU 6447][YJJ&#39;s Salesman][2018CCPC网络选拔赛 1010][离散化+线段树+DP]

链接: http://acm.hdu.edu.cn/showproblem.php?pid=6447 题意: 左上角(0,0),右下角(10^9,10^9)的网格,其中有n(1<=n<=10^5)个方格内有权值. 一次只能沿右,下,右下三个方向走一个格子,只有沿右下方向走到格子里才可以获得权值. 问从(0,0)到(10^9,10^9)的路径最大权值是多少. 思路: 网格路径权值问题,第一感考虑DP,x从上往下,y从左往右刷表,状态转移方程为dp[i][j]=max(dp[i-1][j],dp[

hdu 3016 Man Down (线段树 + dp)

题目大意: 是男人就下一般层...没什么可以多说的吧. 注意只能垂直下落. 思路分析: 后面求最大值的过程很容易想到是一个dp的过程 . 因为每一个plane 都只能从左边 从右边下两种状态. 然后我们所需要处理的问题就是 ,你如何能快速知道往左边下到哪里,往右边下到哪里. 这就是线段树的预处理. 讲线段按照高度排序. 然后按照高度从小到大加入到树中. 然后去寻找左端点 和 右端点最近覆盖的线段的编号. #include <cstdio> #include <iostream> #

HDU 3642 线段树+离散化+扫描线

题意:给你N个长方体的左下角和右上角坐标,问你空间中有多少体积是被大于两个不同的立方体覆盖的.x,y~10^6 z~500 考虑到给的z比较小,所以可以直接枚举z,然后跑二维的扫描线就好. 关于处理被不同的线段覆盖三次的问题,可以维护四个信息,cnt,once,twice,more,然后相互推出结果就好. #include <cstdio> #include <cstring> #include <vector> #include <algorithm> #

HDU6447 YJJ&#39;s Salesman 2018中国大学生程序设计竞赛 - 网络选拔赛1010 离散化+线段树+DP

YJJ's Salesman Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 253    Accepted Submission(s): 62 Problem Description YJJ is a salesman who has traveled through western country. YJJ is always on

hdu 5877 线段树(2016 ACM/ICPC Asia Regional Dalian Online)

Weak Pair Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 262144/262144 K (Java/Others)Total Submission(s): 439    Accepted Submission(s): 155 Problem Description You are given a rooted tree of N nodes, labeled from 1 to N. To the ith node a