「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≤ ...
随机推荐
- mysql用户和授权
CREATE USER 'monitor'@'10.224.32.%' IDENTIFIED BY '123@abAB'; mysql> GRANT select,insert,update O ...
- 洛谷 P3400 仓鼠窝
卡常 #pragma GCC optimize(2) #include<cstdio> #include<algorithm> #include<cstring> ...
- Marriage Ceremonies LightOJ - 1011
Marriage Ceremonies LightOJ - 1011 常规状压dp.popcount(S)表示S集合中元素数量.ans[S]表示S中的女性与前popcount(S)个男性结婚的最大收益 ...
- Easy Game LightOJ - 1031
Easy Game LightOJ - 1031 upd:似乎有复杂度更优越的做法,见http://www.cnblogs.com/hehe54321/p/8431020.html 题意:A和B玩一个 ...
- Palindrome Partitioning LightOJ - 1044(回文串最小分割数,O(n^2)预处理子串是否回文)
题意:将一个字符串分割成最少的字符串,使得分割出的每个字符串都是回文串.输出最小的分割数. 方法(自己的):先O(n^2)(用某个点或某个空区间开始,每次向左右扩展各一个的方法)处理出所有子串是否回文 ...
- XON/OFF
#define XON 0x11#define XOFF 0x13查找ASCII码表,这两个对应的是DC1(设备控制1)和DC3(设备控制3) X/ON和X/OFF为开启和关闭发送器的信号.X /ON ...
- word-wrap与word-break为长单词换行
如果你遇到长串英文单词或者url换行的问题,这时候就需要用到word-wrap与word-break这2个css属性啦. word-wrap:break-word;长单词与url地址自动换行. wor ...
- python_11(网络编程)
第1章 ucp协议 1.1 特性 1.2 缺陷 1.3 UDP协议实时通信 第2章 socket的更多方法 2.1 面向锁的套接字方法 2.1.1 blocking设置非阻塞 2.1.2 Blocki ...
- 用PDFMiner从PDF中提取文本文字
1.下载并安装PDFMiner 从https://pypi.python.org/pypi/pdfminer/下载PDFMineer wget https://pypi.python.org/pack ...
- Sqlserver调用WebApi
原文地址 http://www.cnblogs.com/lflyq/p/6065160.html sp_configure 'show advanced options', 1;GORECONFI ...