God Knows 线段树维护单调栈
来源:互联网 发布:abaqus软件 编辑:程序博客网 时间:2024/06/06 03:10
题意
分析
不难分析到这题实际就是要求一个极长的上升子序列,使得其权值和最小。
首先考虑最暴力的dp:设f[i]表示以i结尾且不考虑后面元素时的极长上升子序列最小值。转移的话,就可以选择所有满足可以转移且转移后仍为极大的j来转移即可。复杂度是O(n^2)
接下来用到的姿势跟bzoj 2957比较类似,都是用线段树来维护一个单调栈的贡献。
我们把元素按照p[i]来排序,那么当我们要转移f[i]时,可以用来转移的j一定是这些数构成的单调栈上的数。也就是所以p[i]为下标,i为单调栈元素。那么我们要维护的实际上就是一个区间内单调栈的最小值。
那么我们在dp的时候,先在线段树中查询[1,p[i]]的值,把f[i]求出来,然后把线段树的p[i]位置加入一个i即可。
用线段树维护单调栈的具体操作就是每个节点记录只考虑当前区间所构成的单调栈的贡献和栈顶元素。在合并儿子的时候,右儿子的单调栈肯定是不变的,那么我们就可以递归计算左儿子的贡献。
而左儿子油杯分成了两部分,设为l和r。
设右儿子的栈顶元素为mx,若mx[r]>mx那么l的单调栈肯定是不变的,然后递归计算r的贡献。若mx[r]
代码
#include<iostream>#include<cstdio>#include<cstdlib>#include<cstring>#include<algorithm>using namespace std;const int N=200005;const int inf=2000000000;int n,p[N],c[N],f[N];struct tree{int l,r,mx,mn;}t[N*5];int read(){ int x=0,f=1;char ch=getchar(); while (ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while (ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} return x*f;}int calc(int d,int l,int r,int x){ if (l==r) return t[d].mx>x?t[d].mn:inf; int mid=(l+r)/2; if (t[d*2+1].mx>x) return min(t[d].l,calc(d*2+1,mid+1,r,x)); else return calc(d*2,l,mid,x);}void ins(int d,int l,int r,int x,int y,int z){ if (l==r) { t[d].mn=z;t[d].mx=y; return; } int mid=(l+r)/2; if (x<=mid) ins(d*2,l,mid,x,y,z); else ins(d*2+1,mid+1,r,x,y,z); t[d].r=t[d*2+1].mn; t[d].l=calc(d*2,l,mid,t[d*2+1].mx); t[d].mx=max(t[d*2].mx,t[d*2+1].mx); t[d].mn=min(t[d].l,t[d].r);}pair<int,int> query(int d,int l,int r,int x,int y){ if (x>y) return make_pair(inf,0); if (l==x&&r==y) return make_pair(t[d].mn,t[d].mx); int mid=(l+r)/2; if (y<=mid) return query(d*2,l,mid,x,y); else { pair<int,int> u=query(d*2+1,mid+1,r,mid+1,y); return make_pair(min(u.first,calc(d*2,l,mid,u.second)),max(u.second,t[d*2].mx)); }}int main(){ freopen("knows.in","r",stdin);freopen("knows.out","w",stdout); n=read(); for (int i=1;i<=n;i++) p[i]=read(); for (int i=1;i<=n;i++) c[i]=read(); for (int i=1;i<=n*4;i++) t[i].mn=t[i].l=t[i].r=inf; int mn=inf; for (int i=1;i<=n;i++) { f[i]=c[i];mn=min(mn,p[i]); if (p[i]>mn) f[i]+=query(1,1,n,1,p[i]).first; ins(1,1,n,p[i],i,f[i]); } int mx=0,ans=inf; for (int i=n;i>=1;i--) if (p[i]>mx) mx=p[i],ans=min(ans,f[i]); printf("%d",ans); return 0;}
阅读全文
0 0
- God Knows 线段树维护单调栈
- 【线段树维护单调栈】【JZOJ 5402】 God Knows
- 线段树 God Knows
- 【技巧】线段树维护区间单调栈
- bzoj 2957: 楼房重建 线段树维护单调栈
- 【JZOJ5402】God Knows
- [日常训练] God Knows
- UESTC 8 God Only Knows!
- bzoj3956 -- 单调栈 + 线段树
- God knows how I miss him!
- [CDOJ 8] God Only Knows! [AC自动机]
- UESTC 8 God Only Knows! AC自动机
- [BZOJ]1012 [JSOI2008]最大数maxnumber (线段树维护区间最值 || 单调栈+二分查找)
- bzoj 1012 最大数(线段树|单调队列|单调栈)
- Sliding Window(单调队列维护或线段树求区间最大最小值)
- HDU5033-Building(维护单调栈)
- CodeForces601D【单调栈维护最大值】
- [BZOJ3956]Count(单调栈+线段树)
- Detection of Extraterrestrial KMP匹配 重复k次子串 好题
- HDU 1846 Brave Game 博弈论
- Fill the Square UVA
- ScrollView中嵌套ListView只显示一行的问题
- 第九章 聚类
- God Knows 线段树维护单调栈
- python3实现一维数组求最大值返回参数需要注意的地方
- 第一次用博客!
- 浙大版《数据结构(第2版)》题目集 简单计算器
- 动画H5
- 关于input框change事件和propertychange事件的区别
- 解决Ubuntu中vi命令的编辑模式下不能正常使用方向键和退格键的问题
- 序
- html5_document简单使用