牛客网-火车票订购【离散化+线段树】

火车经过X站,火车最大载客人数为m,有n个订票请求,请求订购从a站到b站的k张票,若能满足订购要求则输出1,否则输出0。
在这里插入图片描述
半个月终于刷完了NK的200多道题,没想到在最后这里会遇到线段苏,首先,暴力很好写,维护一个区间,区间值初始为m,每次一个查询就把相应区间的载客人数减去相应人数,如果不够减就是0,否则为1,但是这道题很骚,不给数据范围,试了之后发现不行,数据太大

链接:https://www.nowcoder.com/questionTerminal/e65887ca7bf14b1b947073f544a6f4f4?f=discussion
来源:牛客网
不通过
您的代码已保存
答案错误:您提交的程序没有通过所有的测试用例
case通过率为14.74%
用例:
463426784 999969204 415
对应输出应该为:
1
你的输出为:
空.请检查一下你的代码,有没有循环输入处理多个case.

对这种情况,显然需要一手离散化,离散之后再进行操作,however,离散化后的效率依然跟不上

struct E {
	ll from, to, num;
	E(ll a = 0, ll b = 0, ll c = 0) { from = a, to = b, num = c; }
};

int main() {
	ll n, m;
	while (cin >> n >> m) {
		//v1存储所有的请求  v2存储离散化后的站点
		vector<E> v1; set<ll> s; vec v2, v3;
		ll a, b, c;
		for (int i = 0; i < n; i++) {
			cin >> a >> b >> c; v1.push_back(E(a, b, c));
			s.insert(a); s.insert(b); //离散化
		}
		for (set<ll>::iterator i = s.begin(); i != s.end(); i++)
			v2.push_back((*i)),v3.push_back(m); //将离散化后的所有站点存储到vector中
		sort(v2.begin(), v2.end());//从小到大排序

		for (unsigned i = 0; i < v1.size(); i++) {
			E t = v1[i];
			ll id1 = lower_bound(v2.begin(), v2.end(), t.from) - v2.begin();
			ll id2 = lower_bound(v2.begin(), v2.end(), t.to) - v2.begin();
			ll maxN = 0, num = t.num, sign = 1;
			if (num > m) { cout << 0 << endl; continue; }
			for (int j = id1; j <= id2 && sign; j++) {
				if (v3[j] < num) { sign = 0; break; }//该位置没有这么多名额了
			}
			if (sign) {
				cout << 1 << endl;
				for (int j = id1; j <= id2 && sign; j++)
					v3[j] -= num;
			}
			else cout << 0 << endl;
		}
	}
}

此时我们注意到,这个问题完全是一个区间修改,区间查询的问题,我们不断的修改某个区间的值(买票上车),判断能否满足订购要求时需要查询这一段区间内的最小值,经典的RMQ问题,直接线段树即可

#include <cstdio>
#include <cstring>
#include <algorithm>
#define MAX 100000

using namespace std;

int tree[MAX << 3], lazy[MAX << 3];
int a[MAX], b[MAX], k[MAX];

int discrete(int* a, int* b, int n) {
    int temp[MAX << 1], len = 0;
    for(int i = 0; i < n; i++) {
        temp[len++] = a[i];
        temp[len++] = b[i];
    }
    sort(temp, temp + len);
    len = unique(temp, temp + len) - temp;
    for(int i = 0; i < n; i++) {
        a[i] = lower_bound(temp, temp + len, a[i]) - temp;
        b[i] = lower_bound(temp, temp + len, b[i]) - temp;
    }
    return len;
}

int getmax(int a, int b) {
    return a >= b ? a : b;
}

void build() {
    memset(tree, 0, sizeof(tree));
    memset(lazy, 0, sizeof(lazy));
    return;
}

void pushup(int root) {
    tree[root] = getmax(tree[root << 1], tree[root << 1 | 1]);
    return;
}

void pushdown(int root) {
    if(lazy[root] == 0) return;
    tree[root << 1] += lazy[root];
    tree[root << 1 | 1] += lazy[root];
    lazy[root << 1] += lazy[root];
    lazy[root << 1 | 1] += lazy[root];
    lazy[root] = 0;
    return;
}

void update(int a, int b, int k, int l, int r, int root) {
    if(a <= l && r <= b) {
        tree[root] += k;
        lazy[root] += k;
        return;
    }
    pushdown(root);
    int mid = (l + r) >> 1;
    if(a <= mid) update(a, b, k, l, mid, root << 1);
    if(mid + 1 <= b) update(a, b, k, mid + 1, r, root << 1 | 1);
    pushup(root);
}

int query(int a, int b, int l, int r, int root) {
    int ans = 0;
    if(a <= l && r <= b) return tree[root];
    pushdown(root);
    int mid = (l + r) >> 1;
    if(a <= mid) ans = getmax(ans, query(a, b, l, mid, root << 1));
    if(mid + 1 <= b) ans = getmax(ans, query(a, b, mid + 1, r, root << 1 | 1));
    return ans;
}

int main() {
    int n = 0, m = 0, len = 0;
    while(scanf("%d%d", &n, &m) != EOF) {
        for(int i = 0; i < n; i++)
            scanf("%d%d%d", &a[i], &b[i], &k[i]);
        //建树
        build();
        //对所有车站做离散化并拿到真实的车站数
        len = discrete(a, b, n);
        for(int i = 0; i < n; i++) {
            //区间查询+区间修改
            if(query(a[i], b[i], 0, len - 1, 1) + k[i] <= m) {
                update(a[i], b[i], k[i], 0, len - 1, 1);
                printf("1\n");
            }
            else printf("0\n");
        }
    }
    return 0;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值