hdu 3016 线段树+dp
用线段树由低到高覆盖每一层台阶的长度,根据线段左右两端连边,然后由高到底DP即可
#include <stdio.h> #include <algorithm> using namespace std; const int maxn= 200001; const int mincost=-200000000; struct Pool { int to,pre; }pool[maxn<<1]; int p[maxn<<1],top,n; int dp[maxn]; void addedge(int x,int y) { pool[++top].to=y; pool[top].pre=p[x]; p[x]=top; } struct datb { int h,xl,xr,value; bool operator <(const datb &t)const { return h<t.h; } }d[maxn]; int m[maxn<<2],lazy[maxn<<2]; bool defi[maxn<<2]; void pushdown(int rt) { if(lazy[rt]!=-1) { m[rt]=lazy[rt<<1]=lazy[rt<<1|1]=lazy[rt]; defi[rt]=true,lazy[rt]=-1; } } void pushup(int rt) { if(defi[rt<<1]==true&&defi[rt<<1|1]==true&&m[rt<<1]==m[rt<<1|1]) { defi[rt]=true; m[rt]=m[rt<<1]; } else { defi[rt]=false; } } void init() { m[1]=0; defi[1]=true; lazy[1]=0; top=0; for(int i=0;i<=n;i++) { p[i]=0; dp[i]=mincost; } } void change(int rt,int l,int r,int x,int y,int s) { if(x<=l&&y>=r) { m[rt]=s; lazy[rt]=s; defi[rt]=true; return ; } pushdown(rt); int mid=(l+r)>>1; if(mid>=x) change(rt<<1,l,mid,x,y,s); if(mid<y) change(rt<<1|1,mid+1,r,x,y,s); pushup(rt); } int find(int rt,int l,int r,int k) { pushdown(rt); if(r>=k&&l<=k&&defi[rt]==true) return m[rt]; int mid=(l+r)>>1; if(mid>=k) return find(rt<<1,l,mid,k); return find(rt<<1|1,mid+1,r,k); } int main() { int t1,t2; while(scanf("%d",&n)!=EOF) { init(); for(int i=1;i<=n;i++) scanf("%d%d%d%d",&d[i].h,&d[i].xl,&d[i].xr,&d[i].value); sort(d+1,d+1+n); top=0; for(int i=1;i<=n;i++) { t1=find(1,1,100000,d[i].xl); t2=find(1,1,100000,d[i].xr); //printf("%d %d\n",t1,t2); addedge(i,t1); addedge(i,t2); change(1,1,100000,d[i].xl,d[i].xr,i); } dp[n]=d[n].value+100; for(int i=n;i>=1;i--) { for(int j=p[i];j;j=pool[j].pre) { int t=pool[j].to; dp[t]=max(dp[t],dp[i]+d[t].value); } } if(dp[0]<=0) printf("-1\n"); else printf("%d\n",dp[0]); /*for(int i=1;i<=n;i++) { printf("%d: ",d[i].h); for(int j=p[i];j;j=pool[j].pre) printf("%d ",pool[j].to); printf("\n"); }*/ } }