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]的点

View Code
#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;
}

 

posted @ 2012-04-13 16:30  枕边梦  阅读(401)  评论(0编辑  收藏  举报