hdu3607 Traversal (dp+离散+线段树)
很明显的状态转移方程式:dp[i]=max(dp[j])+g[i], (0<=j<i && h[i]>h[j])
不过注意到题目中n的范围有10000 ,n^2的算法…………
我们可以用线段树优化一下
先对高度离散化,作为线段树左右区间的端点
这样,求dp[i]时,只需要查出高度(0,h[i]-1]范围内的最大值t,那么dp[i]=t+g[i], 之后,接着,更新线段树中高度为g[i],值为dp[i]的点
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<iostream> #include<algorithm> #include<string> #include<map> using namespace std; const int N = 100000+10; struct node { int l,r,maxx; }p[N*3]; int n,dp[N],g[N],h[N]; map<int,int> ms; void bulid(int s,int t,int k) { p[k].l=s,p[k].r=t; p[k].maxx=0; if(s==t) return ; int kl=k<<1,kr=kl+1,mid=(s+t)>>1; bulid(s,mid,kl); bulid(mid+1,t,kr); } void update(int k,int tt,int key) { if(p[k].l==tt && p[k].r==tt) { p[k].maxx=max(key,p[k].maxx); return ; } int kl=k<<1,kr=kl+1,mid=(p[k].l+p[k].r)>>1; if(tt<=mid) update(kl,tt,key); else update(kr,tt,key); p[k].maxx=max(p[kl].maxx,p[kr].maxx); } int query(int k,int l,int r) { if(p[k].l>=l && p[k].r<=r) return p[k].maxx; int kl=k<<1,kr=kl+1,mid=(p[k].l+p[k].r)>>1; int a=0,b=0; if(l<=mid) a=query(kl,l,r); if(r>mid) b=query(kr,l,r); return max(a,b); } int main() { while(scanf("%d",&n)==1) { ms.clear(); for(int i=0;i<n;i++) { scanf("%d %d",&h[i],&g[i]); ms[h[i]]=10; } map<int,int>::iterator it=ms.begin(); int t=1; for(;it!=ms.end();it++) it->second=t++; bulid(1,t,1); dp[0]=g[0]; update(1,ms[h[0]],dp[0]); int ans=dp[0]; for(int i=1;i<n;i++) { if(ms[h[i]]!=1) dp[i]=query(1,1,ms[h[i]]-1)+g[i]; else dp[i]=g[i]; update(1,ms[h[i]],dp[i]); ans=max(ans,dp[i]); } printf("%d\n",ans); } return 0; }