codeforces 777 E. Hanoi Factory(线段树||栈)

http://codeforces.com/contest/777/problem/E
题意:
有n个圆环,分别有内径r,和外径R和高度h 圆环 x 可以放在圆环 y上 需要满足条件 R x &lt; = R y Rx&lt;=Ry Rx<=Ry R x &gt; r y Rx&gt;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 &gt; r k Rx&gt;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
空间大小
时间复杂度
*/
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值