这题的思路是:将板子根据高度从低到高排序。用线段树找到当前木板的左边和右边的下一个木板的id,不断覆盖新的木板。
然后用dp[i]表示在第i个木板的最大能量,根据找到的visl和visr不断下跳,找到最优解。
由于做题注意力不集中和对线段树不够熟悉。出现了3个错误,找了我好久,太粗心了。
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
const int N=100005;
int id[N*4],lazy[N*4];
int dp[N];//在第i块板上的最大能量
struct node{
int h,xl,xr,val;
int visl,visr;//左右能到达木板id
}pk[N];
int cmp(node a,node b){
return a.h<b.h;
}
void build(int l,int r,int rt){
id[rt]=0;lazy[rt]=0;
if(l==r)
return;
int m=(l+r)/2;
build(lson);
build(rson);
}
void pushdown(int rt){
if(lazy[rt]!=0){
id[rt*2]=id[rt*2+1]=id[rt];
lazy[rt*2]=lazy[rt*2+1]=1;//--1.忘了这句..
lazy[rt]=0;
}
}
void push_up(int rt){
//单点查询所以不需要向上维护
}
void update(int a,int b,int c,int l,int r,int rt){//线段更新 覆盖
if(a<=l&&b>=r){
id[rt]=c;lazy[rt]=1;
return;
}
pushdown(rt);
int m=(l+r)/2;
if(a<=m)
update(a,b,c,lson);
if(b>m)
update(a,b,c,rson);
push_up(rt);
}
int query(int p,int l,int r,int rt){//单点查询
if(l==r){
return id[rt];
}
pushdown(rt);
int m=(l+r)/2;
if(p<=m)//--2.写成l..
return query(p,lson);
if(p>m)//--写成r..
return query(p,rson);
}
int main(){
int n;
while(cin>>n){
cnt=0;
for(int i=1;i<=n;i++){
scanf("%d %d %d %d",&pk[i].h,&pk[i].xl,&pk[i].xr,&pk[i].val);
//x[cnt++]=pk[i].xl;x[cnt++]=pk[i].xr;由于界是10W,所以不用离散化
}
//int nn=unique(x,x+cnt)-x;
build(1,N,1);
sort(pk+1,pk+n+1,cmp);
for(int i=1;i<=n;i++){
pk[i].visl=query(pk[i].xl,1,N,1);
pk[i].visr=query(pk[i].xr,1,N,1);
update(pk[i].xl,pk[i].xr,i,1,N,1);
}
memset(dp,-1,sizeof dp);
dp[n]=100+pk[n].val;
for(int i=n;i>0;i--){//--3.写成了i++
if(dp[i]==-1) continue;
int l=pk[i].visl,r=pk[i].visr;
dp[l]=max(dp[l],dp[i]+pk[l].val);
dp[r]=max(dp[r],dp[i]+pk[r].val);
}
printf("%d\n",dp[0]);
}
return 0;
}