解题思路
跟求最长不下降子系列的题差不多,那道题变量是顺序和数值大小,这道题是两条边长。
先把一个积木分三个情况存下来(有无数个积木,不用担心同一个使用多次),然后先按长(宽)为关键字排序,按序给每个编号(即离散化),注意长(宽)相同的编号也要相同。然后再按宽(长)排一次序,剩下的做法就是求最长不下降子系列的做法,但注意当宽(长)相同时,要先把他们都算出来,再分别插入,不然会算重。
代码
#include<iostream>
#include<cstdio>
#include<algorithm>
#define ll long long
using namespace std;
ll n,cnt,t,x,y,z,ans,tree[300010],f[300010];
struct c{
ll a,b,c,id;
}a[300010];
bool cmp1(c l,c r)
{
if(l.a==r.a) return l.b<r.b;
return l.a<r.a;
}
bool cmp2(c l,c r)
{
if(l.b==r.b)return l.a<r.a;
return l.b<r.b;
}
void add(ll x,ll c)
{
for(int i=x;i<=cnt;i+=i&(-i))
tree[i]=max(tree[i],c);
}
ll find(ll x)
{
ll ans=0;
for(int i=x;i;i-=i&(-i))
ans=max(ans,tree[i]);
return ans;
}
int main(){
scanf("%lld",&n);
for(int i=1;i<=n;i++)
{
scanf("%lld%lld%lld",&x,&y,&z);
a[++cnt].a=min(x,y),a[cnt].b=max(x,y),a[cnt].c=z;
a[++cnt].a=min(z,y),a[cnt].b=max(z,y),a[cnt].c=x;
a[++cnt].a=min(x,z),a[cnt].b=max(x,z),a[cnt].c=y;
}
sort(a+1,a+cnt+1,cmp1);
a[1].id=++t;
for(int i=2;i<=cnt;i++)
{
if(a[i-1].a!=a[i].a)
a[i].id=++t;
else
a[i].id=t;
}
sort(a+1,a+cnt+1,cmp2);
for(int i=1;i<=cnt;i++)
{
int j=i;
while(j<=cnt&&a[j].b==a[i].b)
{
f[j]=find(a[j].id-1)+a[j].c;
j++;
}
for(int k=i;k<j;k++)
add(a[k].id,f[k]);
i=j-1;
}
for(int i=1;i<=cnt;i++)
ans=max(ans,f[i]);
printf("%lld",ans);
}