以每个方块左右坐标区间为节点建立字典树,每个节点保存这个区间对应的方块的下标,将方块按照高度排序。
如何得到第i个方块可以移动到的两个方块呢?将所有方块排完序,将前i-1个方块放入字典树,根据第i个方块的左右坐标,分别进行单点查询即可,将下一个位置保存。
最后的DP转移方程d[i]=max(d[i].left,d[i].right)+d[i].val;
AC代码:
#include<cstdio>
#include<algorithm>
using namespace std;
const int maxn=1e5+5;
struct node{
int l,r,ind;
}tree[maxn*4];
struct point{
int l,r,h,val;
point(){
}
point(int h,int l,int r,int val):h(h),l(l),r(r),val(val){
}
bool operator <(const point &p)const{
return h<p.h;
}
}plank[maxn];
void Build(int l,int r,int cur){ //建树并初始化为floor
tree[cur].l=l;
tree[cur].r=r;
tree[cur].ind=0;
if(l==r) return;
Build(l,(l+r)>>1,cur<<1);
Build((l+r)/2+1,r,(cur<<1)+1);
}
int ind;
void Insert(int l,int r,int cur){ //更新区间的值
//printf("%d %d\n",l,r);
int ll=tree[cur].l,rr=tree[cur].r;
if(l==ll&&r==rr) {
tree[cur].ind=ind;
return;
}
int mid=(ll+rr)>>1;
if(r<=mid) Insert(l,r,cur<<1);
else if(l>=mid+1) Insert(l,r,(cur<<1)+1);
else {
Insert(l,mid,cur<<1);
Insert(mid+1,r,(cur<<1)+1);
}
}
int val;
int Search(int cur){ //搜索可以到达的下一个格子区间,返回下标
int l=tree[cur].l,r=tree[cur].r;
if(l==r) return tree[cur].ind;
int ind=tree[cur].ind;
int mid=(l+r)>>1;
int a;
if(val<=mid) a=Search(cur<<1);
else a=Search((cur<<1)+1);
return plank[ind].h>plank[a].h?ind:a;
}
int main(){
plank[0]=point(0,0,0,0);
int n;
while(scanf("%d",&n)==1){
int l,r,h,v,width=-1;
for(int i=1;i<=n;++i) {
scanf("%d%d%d%d",&h,&l,&r,&v);
width=max(width,r);
plank[i]=point(h,l,r,v);
}
Build(1,width,1);
sort(plank+1,plank+n+1); //按高度排序
for(int i=1;i<=n;++i){
int l=plank[i].l,r=plank[i].r;
val=l;
plank[i].l=Search(1);
val=r;
plank[i].r=Search(1);
//printf("%d %d\n",plank[i].l,plank[i].r);
ind=i;
Insert(l,r,1);
}
for(int i=1;i<=n;++i){
int l=plank[i].l,r=plank[i].r;
plank[i].val+=max(plank[l].val,plank[r].val);
}
if(plank[n].val+100<=0) printf("-1\n");
else printf("%d\n",plank[n].val+100);
}
return 0;
}
如有不当之处欢迎指出!