「BZOJ1537」Aut – The Bus(变形Dp+线段树/树状数组 最优值维护)
网格图给予我的第一反应就是一个状态 f[i][j] 表示走到第 (i,j) 这个位置的最大价值。
由于只能往下或往右走转移就变得显然了:
f[i][j]=max{f[i-1][j], f[i][j-1]}+a[i][j]
但是面对庞大的数据范围,再优秀的电脑也无法驾驭 百亿亿 的时间复杂度,与 百亿亿 的空间复杂度。
其实只要稍加思考我们就可以发现,枚举那些没有价值的 (x,y) 的坐标是多余的,所以我们只需要枚举有价值的点,在进行Dp转移就会起到加速。
因此新的状态即为:f[i] 表示到达第 i 个点的最大价值(Ps:为了避免后效性应先把一维的坐标进行排序,原因即是当前的状态只可能从最近的上一次转移而来),所以转移即为:
f[i]=max{f[j]}+a[i] ( 0<j≤i-1,x[j]≤x[i],y[j]≤y[i] )
虽然此时它优秀了不少,但是面对 1≤ n ≤10^9 数据范围,它还是离 AC 此题相隔甚远QAQ。
所以对于现在的转移,i 的枚举无法避免,但是对于 MAX 的最优求解仍有极大的优化空间。所以此时我们面临的问题是: f[j] 的转移状态能否从一些连续的数值范围内得到呢,其实仔细思考一下就可以得到一个规律,对于一个 f[i] 它的坐标 (x[i], y[i]) ,假设我们将 x[i] 进行了排序,显然仍以的 x[i] 都满足转移的条件,所以我们转移只可能来自 1 ˜ y[i]-1 这个范围内,所以只要快速求得1 ˜ y[i]-1 内的转移的最大值,就可解决此题!
显然我们可以维护一个线段树,来维护前 k 种 y[i] 的转移的最大值(由于它是再求前缀的最优值,我们也可以用树状数组来维护)。
在维护时,我们可以通过 二分查找 快速求得当前的 y[i] 位于第几小的纵向坐标,再根据一种优秀的数据结构来解决最优值的维护。
所以再最后献上本人的专属代码(线段树版本)与网络大佬的代码(树状数组版本):
首先是蒟蒻本人的专属代码: #include<bits/stdc++.h>
using namespace std;
const int MAXN_TREE=;
const int MAXN=; inline int read(){
int ret=;
char ch=getchar();
while (ch<'' || ch>'') ch=getchar();
while (ch>='' && ch<='') ret=ret*+ch-'', ch=getchar();
return ret;
}
// 读入优化 struct You{
int x, y, val;
}a[MAXN];
int b[MAXN], tree[MAXN_TREE], Ans, n; inline bool cmp(const You&x, const You&y){
return x.x<y.x || (x.x==y.x && x.y<y.y);
} inline int find(int x){
int l=,r=n;
while(l<=r){
int mid=(l+r)>>;
if(b[mid]<x)l=mid+;
else if(b[mid]==x)return mid;
else r=mid-;
}
}
// 二分查找 inline int query(int root, int l, int r, int x, int y){
if (y<l || x>r) return ;
if (l>=x && r<=y) return tree[root];
int mid=(l+r)>>;
return max(query(root+root, l, mid, x, y), query(root+root+, mid+, r, x, y));
}
// 线段树区间查找 inline void change(int root, int l, int r, int x, int sum){
if (r<x || l>x) return;
if (l==r && l==x){
tree[root]=sum;
return;
}
int mid=(l+r)>>;
change(root+root, l, mid, x, sum);
change(root+root+, mid+, r, x, sum);
tree[root]=max(tree[root+root], tree[root+root+]);
}
//线段树单点修改 int main(){
n=read(), n=read(), n=read();
for (int i=; i<=n; i++) a[i].x=read(), a[i].y=read(), a[i].val=read(), b[i]=a[i].y;
sort(a+, a++n, cmp);
sort(b+, b++n);
for (int i=; i<=n; i++){
int Place=find(a[i].y); // 寻找当前 y[i] 为第Place小的横向坐标
int Sum=a[i].val+query(, , n, , Place);
change(, , n, Place, Sum); //插入当前转移的值
Ans=max(Ans, Sum);
}
printf("%d\n", Ans);
return ;
}
大佬的代码,来自与http://hzwer.com/3248.html/
未经允许复制下来,希望大佬不要追究法律责任QWQ,所以我就不做详细
介绍了: #include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
inline int read()
{
int x=;char ch=getchar();
while(ch<''||ch>'')ch=getchar();
while(ch>=''&&ch<=''){x=x*+ch-'';ch=getchar();}
return x;
}
int n,ans;
int t[],hash[];
struct data{int x,y,p;}a[];
inline bool cmp(data a,data b)
{if(a.x==b.x)return a.y<b.y;return a.x<b.x;}
int find(int x)
{
int l=,r=n;
while(l<=r)
{
int mid=(l+r)>>;
if(hash[mid]<x)l=mid+;
else if(hash[mid]==x)return mid;
else r=mid-;
}
}
inline int lowbit(int x){return x&(-x);}
void change(int x,int val)
{
for(int i=x;i<=n;i+=lowbit(i))
t[i]=max(val,t[i]);
}
int ask(int x)
{
int tmp=;
for(int i=x;i>;i-=lowbit(i))
tmp=max(tmp,t[i]);
return tmp;
}
int main()
{
n=read(),n=read(),n=read();
for(int i=;i<=n;i++)
{
a[i].x=read();a[i].y=read();a[i].p=read();
hash[i]=a[i].y;
}
sort(hash+,hash+n+);
sort(a+,a+n+,cmp);
int tmp,pos;
for(int i=;i<=n;i++)
{
pos=find(a[i].y);
tmp=a[i].p+ask(pos);
change(pos,tmp);
ans=max(ans,tmp);
}
printf("%d",ans);
return ;
} 太优美了,蒟蒻在线膜拜!!!
第二篇加油加油,奋斗ing!!!QAQ
「BZOJ1537」Aut – The Bus(变形Dp+线段树/树状数组 最优值维护)的更多相关文章
- 「SDOI2016」储能表(数位dp)
「SDOI2016」储能表(数位dp) 神仙数位 \(dp\) 系列 可能我做题做得少 \(QAQ\) \(f[i][0/1][0/1][0/1]\) 表示第 \(i\) 位 \(n\) 是否到达上界 ...
- 「luogu3380」【模板】二逼平衡树(树套树)
「luogu3380」[模板]二逼平衡树(树套树) 传送门 我写的树套树--线段树套平衡树. 线段树上的每一个节点都是一棵 \(\text{FHQ Treap}\) ,然后我们就可以根据平衡树的基本操 ...
- LOJ #2135. 「ZJOI2015」幻想乡战略游戏(点分树)
题意 给你一颗 \(n\) 个点的树,每个点的度数不超过 \(20\) ,有 \(q\) 次修改点权的操作. 需要动态维护带权重心,也就是找到一个点 \(v\) 使得 \(\displaystyle ...
- LOJ #2359. 「NOIP2016」天天爱跑步(倍增+线段树合并)
题意 LOJ #2359. 「NOIP2016」天天爱跑步 题解 考虑把一个玩家的路径 \((x, y)\) 拆成两条,一条是 \(x\) 到 \(lca\) ( \(x, y\) 最近公共祖先) 的 ...
- LOJ 3089 「BJOI2019」奥术神杖——AC自动机DP+0/1分数规划
题目:https://loj.ac/problem/3089 没想到把根号之类的求对数变成算数平均值.写了个只能得15分的暴力. #include<cstdio> #include< ...
- LOJ 2547 「JSOI2018」防御网络——思路+环DP
题目:https://loj.ac/problem/2547 一条树边 cr->v 会被计算 ( n-siz[v] ) * siz[v] 次.一条环边会被计算几次呢?于是去写了斯坦纳树. #in ...
- LOJ 3056 「HNOI2019」多边形——模型转化+树形DP
题目:https://loj.ac/problem/3056 只会写暴搜.用哈希记忆化之类的. #include<cstdio> #include<cstring> #incl ...
- LOJ2360. 「NOIP2016」换教室【概率DP】【Floyed】【傻逼题】
LINK 思路 先floyed出两点最短路 然后就可以直接\(dp_{i,j,0/1}\)表示前i节课选择换j节,换不换当前这一节的最小贡献 直接可以枚举上一次决策的状态计算概率进行统计就可以了 我变 ...
- 「NOIP2016」「P1850」 换教室(期望dp
题目描述 对于刚上大学的牛牛来说,他面临的第一个问题是如何根据实际情况申请合适的课程. 在可以选择的课程中,有 2n2n 节课程安排在 nn 个时间段上.在第 ii(1 \leq i \leq n1≤ ...
随机推荐
- Hexo - 修改永久链接的默认格式
Hexo的永久链接的默认格式是 :year/:month/:day/:title/,比如访问站点下某一篇文章时,其路径是 2018/04/12/xxxx/,如果我们的文章标题是中文的,那么该路径就会出 ...
- Rsync 实现远程同步
介绍 rsync命令是一个远程数据同步工具,可通过LAN/WAN快速同步多台主机间的文件.rsync使用所谓的“rsync算法”来使本地和远程两个主机之间的文件达到同步,这个算法只传送两个文件的不同部 ...
- new delete 创建回收细节
- python之os、sys和random模块
import os # print(os.getcwd())#获取当前目录,绝对路径# print(os.chdir('../'))#更改当前目录,../的意思是退回上一级目录# print(os.g ...
- 回文树1960. Palindromes and Super Abilities
Bryce1010模板 http://acm.timus.ru/problem.aspx?space=1&num=1960 #include <bits/stdc++.h> usi ...
- Hu矩
close all; clear all; I1=imread('lena.bmp'); angle=; T=[cos(angle),sin(angle),;-sin(angle),cos(angle ...
- AJPFX关于StringBuffer,StringBuilder类总结(二)
StringBuffer,StringBuilder类 总结2需要注意的知识点:1):// String -- >StringBuffer String s = "hel ...
- AJPFX简述Java中this关键字的使用
Java中this关键字的使用主要有两处: 1.构造方法 this指的是调用构造方法进行初始化的对象. //有参构造public Human(String name, int age) { this( ...
- 你干啥的?Lombok
01.Lombok 的自我介绍 Lombok 在官网是这样作自我介绍的: Project Lombok makes java a spicier language by adding 'handler ...
- Java GC机制简要总结(Java垃圾回收的基本工作原理)
第一次编辑 2019-05-07 01:09:39 垃圾回收的对象 程序中的不可用对象(不存活的对象,没有任何引用),或者无用的变量信息等,在程序中长期存在会逐渐占用较多的内存空间,导致没有足够的空间 ...