第i个盘子可以叠在第j个盘子上,当且仅当第i个盘子的外径<=第j个盘子的外径,第i个盘子的外径>第j个盘子的内径。
题解:线段树
对于盘子的内外径进行离散化,以线段数的下标,表示当且内径为i的高度。
将盘子以外径为第一关键字(降序),内径为第二关键字(升序),每次不断将盘子加入,选取可以放置的最大高度。
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#define N 300003
#define LL long long
using namespace std;
struct data{
int a,b,h;
}t[N];
LL tr[N*4],delta[N*4];
int a[N],b[N],n;
int cmp(int x,int y)
{
return a[x]<a[y];
}
int cmp1(data a,data b)
{
return a.b>b.b||a.b==b.b&&a.a>b.a;
}
LL qjmax(int now,int l,int r,int ll,int rr)
{
if (ll<=l&&r<=rr) return tr[now];
int mid=(l+r)/2;
LL ans=0;
if (ll<=mid) ans=max(ans,qjmax(now<<1,l,mid,ll,rr));
if (rr>mid) ans=max(ans,qjmax(now<<1|1,mid+1,r,ll,rr));
return ans;
}
int update(int now)
{
tr[now]=max(tr[now<<1],tr[now<<1|1]);
}
void pointchange(int now,int l,int r,int x,LL v)
{
if (l==r) {
tr[now]=max(tr[now],v);
return;
}
int mid=(l+r)/2;
if (x<=mid) pointchange(now<<1,l,mid,x,v);
else pointchange(now<<1|1,mid+1,r,x,v);
update(now);
}
int main()
{
freopen("a.in","r",stdin);
scanf("%d",&n);
for (int i=1;i<=n;i++)
scanf("%d%d%d",&t[i].a,&t[i].b,&t[i].h),a[i]=t[i].a,b[i]=i,a[i+n]=t[i].b,b[i+n]=i+n;
sort(b+1,b+n*2+1,cmp);
int cnt=0;
for (int i=1;i<=n*2;i++)
if (a[b[i]]!=a[b[i-1]]) {
if (b[i]<=n) t[b[i]].a=++cnt;
else t[b[i]-n].b=++cnt;
}
else{
if (b[i]<=n) t[b[i]].a=cnt;
else t[b[i]-n].b=cnt;
}
sort(t+1,t+n+1,cmp1);
for (int i=1;i<=n;i++) {
// cout<<t[i].a<<" "<<t[i].b<<" "<<t[i].h<<endl;
LL high=qjmax(1,1,cnt,1,t[i].b-1);
pointchange(1,1,cnt,t[i].a,(LL)high+t[i].h);
}
printf("%I64d\n",tr[1]);
}