zoukankan      html  css  js  c++  java
  • [题解] CF609F Frogs and mosquitoes

    前言

    题目链接:洛谷

    题目链接:CodeForces

    题意

    (n) 个区间,每个区间为 ([x_i,x_i+t_i]) ,有 (m) 个事件,事件的位置为 (p_j) ,每个事件会被 (x_i+t_igeq p_j) 的区间中, (x_i) 最小的区间所处理,处理后 (t_i) 会增加 (b_j)。事件如果没有处理,则不会消失。下一个事件出现时,当且仅当没有可以处理的事件。

    输出每个区间处理的事件,和最终的 (t_i)

    思路

    首先可以发现,这些区间的左端点都是不变的,因为题目想要最小的 (x_i) ,所以对于这些区间按照左端点排序。

    可以发现,当前答案这一位为 (k) ,则前 (k-1) 个区间中必没有一个满足条件的,而 (p(pgeq k)) ,前 (p) 个区间至少有一个满足条件,于是可以二分答案。

    而找到这个分界点,就可以找到能处理这个事件的区间,只需要找到能够处理区间最大值的数据结构。

    这里使用的是线段树。第一个二分,二分出 (x_i) 大于 (p_j) 的数字的前驱,设为 (rmax) 。然后再 ([1,rmax]) 中二分当前答案。若 ([1,mid]) 中,最大的 (x_i+t_i) 大于 (p_j) 则代表前 (mid) 个区间可以处理这个事件。

    若没有区间可以处理这个事件,则用一个 multiset 来维护没有被处理的事件,按照 (p_j) 来进行排序,方便以后的区间增长后来处理。

    否则处理完当前的事件,区间变长了,由于只有这一个区间变长,所以只有这个区间可能处理之前没处理过的事件。

    因为用了 multiset ,所以按顺序枚举 multiset 中的元素。知道不能处理下一个事件或是没有事件可以处理为止。

    每处理一个事件,都放入 (slay) 这个 multiset 中,所有可处理的事件处理完之后,在进行删除,否则会炸。

    每次处理后 (slay) 数组需要清空。

    Code

    时间复杂度为 (O(nlog n))

    #include <set>
    #include <cstdio>
    #include <algorithm>
    using namespace std;
    #define LL long long
    const int MAXN = 2e5 + 5;
    multiset<pair<int, int> > st, slay;
    struct Node {
    	int l, r, id;
    	friend bool operator < (Node x, Node y) {
    		return x.l < y.l;
    	}
    };
    bool cmp(Node x, Node y) {
    	return x.id < y.id;
    }
    Node a[MAXN];
    int ans[MAXN], p[MAXN], b[MAXN], n, m;
    LL len[MAXN];
    struct Segment_Node {
    	int l, r;
    	LL maxdata;
    	#define ls (pos << 1)
    	#define rs (pos << 1 | 1)
    };
    struct Segment_Tree {
    	Segment_Node t[MAXN << 2];
    	void Push_Up(int pos) {
    		t[pos].maxdata = max(t[ls].maxdata, t[rs].maxdata);
    	}
    	void Build(int pos, int l, int r) {
    		t[pos].l = l, t[pos].r = r;
    		if (l == r) {
    			t[pos].maxdata = a[l].r;
    			return;
    		}
    		int mid = (l + r) >> 1;
    		Build(ls, l, mid);
    		Build(rs, mid + 1, r);
    		Push_Up(pos);
    	}
    	void Update(int pos, int x, int d) {
    		if (t[pos].l == t[pos].r) {
    			t[pos].maxdata = d;
    			return;
    		}
    		if (t[ls].r >= x)
    			Update(ls, x, d);
    		else
    			Update(rs, x, d);
    		Push_Up(pos);
    	}
    	int Query_Max(int pos, int l, int r) {
    		if (l <= t[pos].l && t[pos].r <= r)
    			return t[pos].maxdata;
    		int res = 0;
    		if (l <= t[ls].r)
    			res = max(res, Query_Max(ls, l, r));
    		if (r >= t[rs].l)
    			res = max(res, Query_Max(rs, l, r));
    		return res;
    	}
    };
    Segment_Tree tree;
    int main() {
    	scanf("%d %d", &n, &m);
    	for (int i = 1, x, t; i <= n; i++) {
    		scanf("%d %d", &x, &t);
    		a[i].l = x, a[i].r = x + t, a[i].id = i;
    	}
    	for (int i = 1; i <= n; i++)
    		len[i] = a[i].r;
    	sort(a + 1, a + 1 + n);
    	tree.Build(1, 1, n);
    	for (int i = 1; i <= m; i++) {
    		scanf("%d %d", &p[i], &b[i]);
    		int l = 1, r = n, rmax = -1, res = -1;
    		while (l <= r) {
    			int mid = (l + r) >> 1;
    			if (a[mid].l <= p[i])
    				l = mid + 1, rmax = mid;
    			else
    				r = mid - 1;
    		}
    		l = 1, r = rmax;
    		while (l <= r) {
    			int mid = (l + r) >> 1;
    			if (tree.Query_Max(1, 1, mid) >= p[i])
    				r = mid - 1, res = mid;
    			else
    				l = mid + 1;
    		}
    		if (res == -1)
    			st.insert(make_pair(p[i], b[i]));
    		else {
    			LL maxlen = len[a[res].id] + b[i];
    			ans[a[res].id]++;
    			for (multiset<pair<int, int> >::iterator it = st.upper_bound(make_pair(a[res].l, 0)); it != st.end(); it++) {
    				if (it->first <= maxlen) {
    					maxlen += it->second;
    					ans[a[res].id]++;
    					slay.insert(*it);
    				}
    				else
    					break;
    			}
    			for (multiset<pair<int, int> >::iterator it = slay.begin(); it != slay.end(); it++) 
    				st.erase(*it);
    			slay.clear();
    			len[a[res].id] = maxlen;
    			tree.Update(1, res, maxlen);
    		}
    	}
    	sort(a + 1, a + 1 + n, cmp);
    	for (int i = 1; i <= n; i++)
    		printf("%d %lld
    ", ans[i], len[i] - a[i].l);
    	return 0;
    }
    
  • 相关阅读:
    mysql 性能监控
    拼接字符
    mysql 存储 2
    mysql 存储过程
    flock
    readfile() file_get_content f
    url_encode和base64
    jsdetox反混淆js内容,解密前端加密参数
    前端加密之使用firefox来解密
    v to ray做渗透测试
  • 原文地址:https://www.cnblogs.com/C202202chenkelin/p/15034131.html
Copyright © 2011-2022 走看看