CSUOJ 1922 Irony Ring 线段树 or 贪心

Description

  There are n irony ring in a factory. The i-th ring has inner radius ai, outer radius bi and height hi. The goal is to select some subset of irony ring to create as high town as possible . The subset of irony ring following condition are satisifed:
  1. outer radiuses form a non-increasing sequence , i.e, one can put the
    j-th ring on the i-th ring only if bj ≤ bi;

  2. the above ring’s outer radius should longer than the below ring’s
    inner radius. That means one can place ring j on the ring i only if
    bj>ai.

  3. The total height of ring used should be maximum possible.

Input
http://acm.csu.edu.cn/csuoj/problemset/problem?pid=1922
Output
Print one integer – the maximum height of the tower that can be obtained.

Sample Input

3
1 5 1
2 6 2
3 7 3
4
1 2 1
1 3 3
4 6 2
5 7 1

Sample Output

6
4

题意:

有n个铁环,每个铁环有内半径ai,外半径bi,还有高度hi,然后要用这些铁环来建一座建筑,放在上面的铁环必须满足:1)上面的外半径bi比下面的外半径bj要小;2)上面的外半径bj要比下面的内半径ai要大,3)要求叠起来最高

解法:

解法有两种,一种是使用线段树,将内径和外径看做区间边界【l,r】 每个戒指算作一个更新,在l,r之间加上高度h,不断维护最大值。 最后输出整个区间的最大值即可。应为l,r的数据范围是1e9 而线段树的合理区间是1e7,所以要离散化。
离散化的方法是: 将所有的l,r排序 ,然后区间更新
线段树的写法是 首先,你把外径从大到小排序
如果外径相等,把内径从大到小排序 之后的顺序,外径就是非递增的 那么对于当前我们枚举第i个ring,外径是S[i].b,内径是S[i].a
这个rin只能放在内径小与S[i].b的上面 我们线段树,第i个叶子维护一个叠起来的东西中,最上面那个ring的内径为i,此时的高度
所以我们只要在线段树中查询[1,S[i].b-1]中的最大值,就是我当前可以放之后的最高高度了(基神强无敌)
线段树写法的的复杂度是nlongn 常数很大
第二种是贪心求解
就是将这些铁环排序,外半径越大的越前面,一样大的话内半径越大的越前面,然后用一个栈来维护当前被叠起来的铁环,还有一个ans值来记录当前的最大的高度,然后每次放一个铁环上来的时候判断当前的条件是否满足,不满足就拿掉当前的铁环,知道满足,然后从新判断当前高度是否比原来的的最大高度大,大的话就更新 复杂度同样为nlongn 常数小
线段树版代码

#include <map>
#include <set>
#include <cmath>
#include <ctime>
#include <stack>
#include <queue>
#include <cstdio>
#include <cctype>
#include <bitset>
#include <string>
#include <vector>
#include <climits>
#include <cstring>
#include <iostream>
#include <iomanip>
#include <algorithm>
#include <functional>
#define fuck(x) cout<<"["<<x<<"]";
#define FIN freopen("input.txt","r",stdin);
#define FOUT freopen("output.txt","w+",stdout);
using namespace std;
typedef long long ll;
typedef pair<ll, ll> pll;
typedef pair<int, int> pii;
typedef pair<double, double> pdd;

const int MX = 1e5 + 5;
const int INF = 0x3f3f3f3f;
const ll INFLL = 0x3f3f3f3f3f3f3f3fLL;
const int mod = 1e9 + 7;

#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define root 1,bsz,1
int n;
struct Data {
    int a, b, h;
    bool operator<(const Data &P)const {
        if(b == P.b) return a > P.a;
        return b > P.b;
    }
} A[MX];
int SB[2 * MX], bsz;
ll MAX[MX << 2];

void push_up(int rt) {
    MAX[rt] = max(MAX[rt << 1], MAX[rt << 1 | 1]);
}
void build(int l, int r, int rt) {
    MAX[rt]=0;
    if(l == r) {
        return;
    }
    int m = (l + r) >> 1;
    build(lson); build(rson);
}
ll query(int L, int R, int l, int r, int rt) {
    if(L <= l && r <= R) {
        return MAX[rt];
    }
    int m = (l + r) >> 1; ll ret = 0;
    if(L <= m) ret = max(ret, query(L, R, lson));
    if(R > m) ret = max(ret, query(L, R, rson));
    return ret;
}
void update(int p, ll x, int l, int r, int rt) {// 此种写法 每次只更新了一个点 复杂度logn
    if(l == r) {
        MAX[rt] = max(MAX[rt], x);
        return;
    }
    int m = (l + r) >> 1;
    if(p <= m) update(p, x, lson);
    else update(p, x, rson);
    push_up(rt);
}

int id(int x) {
    return lower_bound(SB + 1, SB + 1 + bsz, x) - SB;
}
int main() {
    //FIN;
    while(~scanf("%d", &n)) {
        bsz = 0;
        for(int i = 1; i <= n; i++) {
            scanf("%d%d%d", &A[i].a, &A[i].b, &A[i].h);
            SB[++bsz] = A[i].a;
            SB[++bsz] = A[i].b;
        }
        sort(A + 1, A + 1 + n);
        sort(SB + 1, SB + 1 + bsz);
        bsz = unique(SB + 1, SB + 1 + bsz) - SB - 1;// 离散化去重
        for(int i = 1; i <= n; i++) {
            A[i].a = id(A[i].a);
            A[i].b = id(A[i].b);
        }
        build(root);

        for(int i = 1; i <= n; i++) {
            ll now = 1 <= A[i].b - 1 ? query(1, A[i].b - 1, root) : 0;
            update(A[i].a, now + A[i].h, root);
        }

        ll ans = query(1, bsz, root);
        printf("%lld\n", ans);
    }
    return 0;
}

贪心代码

#include<iostream>
#include<queue>
#include<vector>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<stack>
#define fuck(x) cout<<"["<<x<<"]"<<endl
using namespace std;
const int MAX=1e5+10;
class ring
{
public:
    long long  w,n,h;
    ring(long long w,long long n,long long h):w(w),n(n),h(h){}
    ring (){}
};
bool cmp(ring a,ring b)
{
    if(a.w==b.w)
    {
        return a.n>b.n;
    }
    return a.w>b.w;
}
ring rings[MAX];
stack<ring> S;
long long maxhi,nowmaxs;
void my_push(ring ns)
{
    while(!S.empty())
    {
        ring cnt=S.top();
        if(cnt.n>=ns.w)
        {
            S.pop();
            nowmaxs-=cnt.h;
        }
        else break;
    }
    S.push(ns);
    nowmaxs+=ns.h;
    maxhi=max(nowmaxs,maxhi);
}
int main()
{
    int n;
    while(~scanf("%d",&n))
    {
       // fuck(n);
        for(int i=0;i<n;i++)
        {
            scanf("%lld %lld %lld",&rings[i].n,&rings[i].w,&rings[i].h);
            //fuck(rings[i].h);
        }
        sort(rings,rings+n,cmp);
        while(!S.empty())
        {
            S.pop();
        }
        //S.push(ring(1e9+5,0,0));
        maxhi=nowmaxs=0;
        for(int i=0;i<n;i++)
        {
            my_push(rings[i]);
        }
        cout<<maxhi<<endl;
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值