http://codeforces.com/contest/777/problem/E
题意:
有n个圆环,分别有内径r,和外径R和高度h 圆环 x 可以放在圆环 y上 需要满足条件
R
x
<
=
R
y
Rx<=Ry
Rx<=Ry且
R
x
>
r
y
Rx>ry
Rx>ry,相当于上面的外径比下面外径小并且上面不能掉下去,问最高可以叠多高
思路:此题有点像放箱子的问题,可以简化为DAG思考,首先应当按照R从大到小,R相同时,r从大到小(r越小的在上面后面的越不容易掉下去)
方法一:
dp[x]表示对于x个圆环能达到的最大高度,可以得到转移方程
d
p
[
x
]
=
m
a
x
(
d
p
[
x
]
,
d
p
[
k
]
+
h
[
x
]
)
dp[x]=max(dp[x],dp[k]+h[x])
dp[x]=max(dp[x],dp[k]+h[x]) dp[k]是满足上述条件最大的高度,那么就需要从它转移过来,此时就需要用一个数据结构来维护一个区间最小值,可以用线段树或者树状数组,
对于当前x我们查询满足条件的k时只需要满足
R
x
>
r
k
Rx>rk
Rx>rk所以我们就以每个圆环的r建一棵权值线段树(注意离散化),每次查询<R的最大值,单点更新答案即可
方法二:看了题解后发现还有简单的做法,此题目还可用贪心思路来解决,对于排序后 i , j , k i,j,k i,j,k三个圆环,如果j不能放在i上,那么k也一定不能放在i上,具有一定的连续性,那么我们就维护一个以k结尾的最大高度的圆环,我们就需要把前面不能放的全部拿出去,保证现在到k的高度是最大的,那么就可以用栈来模拟这个过程
#include<bits/stdc++.h>
#include<tr1/unordered_map>
#define fi first
#define se second
#define show(a) cout<<a<<endl;
#define show2(a,b) cout<<a<<" "<<b<<endl;
#define show3(a,b,c) cout<<a<<" "<<b<<" "<<c<<endl;
#define max3(a,b,c) max(a,max(b,c))
#define min3(a,b,c) min(a,min(b,c))
using namespace std;
typedef long long ll;
typedef pair<ll, ll> P;
typedef pair<P, int> LP;
const int inf = 0x3f3f3f3f;
const int N = 1e6 + 100;
const ll mod = 1e18+7;
const int base=131;
inline ll mul(ll x,ll y) { return (x*y-(ll)((long double)x*y/mod)*mod+mod)%mod;}
inline ll ksm(ll a,ll b) {ll ans=1;while(b){if(b&1)ans=mul(ans,a);a=mul(a,a),b>>=1;}return ans;}
ll n,m,x,y,cx,cy,flag;
ll a[N],b[N];
ll k,ans,cnt,sum;
ll res,vis[N],mp[1005][1005];
ll tree[N];
vector<int> v;
P mx[N],mi[N];
int st[N];
struct node
{
ll a,b,h;
}no[N];
bool cmp( node a,node b)
{
if(a.b==b.b) return a.a>b.a;//相同外圈时 内圈大的在下面
return a.b>b.b;
}
int getid(int x)
{
return lower_bound(v.begin(),v.end(),x)-v.begin()+1;
}
void pushup(int rt)
{
tree[rt]=max(tree[rt<<1],tree[rt<<1|1]);
}
ll query(int L,int R,int l,int r,int rt)
{
if(L<=l&&r<=R)
{
return tree[rt];
}
int mid=l+r>>1;
ll ans=0;
if(L<=mid) ans=max(ans,query(L,R,l,mid,rt<<1));
if(R>mid) ans=max(ans,query(L,R,mid+1,r,rt<<1|1));
return ans;
}
void update(int pos,ll val,int l,int r,int rt)//ll
{
if(l==r&&l==pos)
{
tree[rt]=max(tree[rt],val);//取最大值
return ;
}
int mid=l+r>>1;
if(pos<=mid) update(pos,val,l,mid,rt<<1);
else update(pos,val,mid+1,r,rt<<1|1);
pushup(rt);
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin>>n;
for(int i=1;i<=n;i++)
{
cin>>no[i].a>>no[i].b>>no[i].h;
v.push_back(no[i].a);
v.push_back(no[i].b);
}
sort(v.begin(),v.end());
v.erase(unique(v.begin(),v.end()),v.end());
sort(no+1,no+n+1,cmp);
int sz=v.size()+1;
//show2("sz",sz)
for(int i=1;i<=n;i++)
{
//show2("query ",getid(no[i].b)-1);
x=query(0,getid(no[i].b)-1,0,sz,1);
//show3(getid(no[i].a),x,x+no[i].h)
update(getid(no[i].a),x+no[i].h,0,sz,1);
}
cout<<query(1,sz,0,sz,1)<<endl;
}
/*
数据范围
是否爆int
空间大小
时间复杂度
*/
方法二
#include<bits/stdc++.h>
#include<tr1/unordered_map>
#define fi first
#define se second
#define show(a) cout<<a<<endl;
#define show2(a,b) cout<<a<<" "<<b<<endl;
#define show3(a,b,c) cout<<a<<" "<<b<<" "<<c<<endl;
#define max3(a,b,c) max(a,max(b,c))
#define min3(a,b,c) min(a,min(b,c))
using namespace std;
typedef long long ll;
typedef pair<ll, ll> P;
typedef pair<P, int> LP;
const int inf = 0x3f3f3f3f;
const int N = 1e6 + 100;
const ll mod = 1e18+7;
const int base=131;
inline ll mul(ll x,ll y) { return (x*y-(ll)((long double)x*y/mod)*mod+mod)%mod;}
inline ll ksm(ll a,ll b) {ll ans=1;while(b){if(b&1)ans=mul(ans,a);a=mul(a,a),b>>=1;}return ans;}
ll n,m,x,y,cx,cy,flag;
ll a[N],b[N];
ll k,ans,cnt,sum;
ll res,vis[N],mp[1005][1005];
ll tree[N];
vector<int> v;
P mx[N],mi[N];
ll dp[N];
struct node
{
ll a,b,h,w;
}no[N];
bool cmp( node a,node b)
{
if(a.b==b.b) return a.a>b.a;
return a.b>b.b;
}
stack<node> st;
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin>>n;
for(int i=1;i<=n;i++)
{
cin>>no[i].a>>no[i].b>>no[i].h;
no[i].w=no[i].h;
}
sort(no+1,no+n+1,cmp);
for(int i=1;i<=n;i++)
{
while(st.size()&&st.top().a>=no[i].b)
st.pop();
if(st.size()) no[i].w+=st.top().w;
ans=max(no[i].w,ans);
st.push(no[i]);
}
cout<<ans;
}
/*
数据范围
是否爆int
空间大小
时间复杂度
*/