P3602 Koishi Loves Segments

P3602 Koishi Loves Segments

大意

给你 \(n\) 条线段,和 \(m\) 个点,要求这些点有一些限制,这些限制是,这个点 \(i\) 不能被超过 \(x_i\) 条线段覆盖,现在问你最多能插入多少条线段。

思路

首先我们能想到的最简单的做法是,考虑每一个点的限制,因为此题显然与你的线段是无关的,我们考虑这样的问题,如果一个点被 \(2\) 条线段覆盖,且存在 \(r_1 < r_2\),不难发现这时候我们保留 \(r_1\) 的这条线段是优的,因为对后续点的影响最小。那对前面的点的影响怎么办呢,我们不需要管,因为如果在此时放入的线段的 \(l\) 来说,这个\(l\) 的约束我们可以直接通过线段树维护解决。

实际上来说,我们可以这样做,对所有的线段按右端点从小大排序,每次处理线段的时候,看看这个线段覆盖的区间 \([l_i, r_i]\) 是否能再覆盖,我们这个时候只需要对于每一个点维护一个能放的剩余数,如果区间 \([l_i, r_i]\) 的最小值 \(v > 0\),那么证明这条线段一定是可以放进去的,我们用线段树修改一下即可,然后继续做这个操作。

代码

#include<iostream>
#include<algorithm>
using namespace std;

#define rep(i, a, b) for(int i = a;i <= b;i ++)
#define lc u << 1
#define rc u << 1 | 1
const int MAXN = 4 * 1e5 + 5;

int n, m;
int ans = 0;
int minx[MAXN << 2], tag[MAXN << 2];
struct node{
	int l, r;
}seg[MAXN];
struct point{
	int pos, x;
}p[MAXN];

void pushup(int u){
	minx[u] = min(minx[lc], minx[rc]);
}

void pushdown(int u){
    if(tag[u]){
        minx[lc] += tag[u];
		tag[lc] += tag[u];
        minx[rc] += tag[u];
		tag[rc] += tag[u];
        tag[u] = 0;
    }
}

void build(int u, int l, int r){
	if(l == r){
		minx[u] = p[l].x;
		return;
	}
	int mid = (l + r) >> 1;
	build(lc, l, mid);
	build(rc, mid + 1, r);
	pushup(u);
}

int ask(int u, int l, int r, int ql, int qr){
	if(ql <= l && r <= qr) return minx[u];
	pushdown(u);
	int mid = (l + r) >> 1;
	int res = 1e9;
	if(ql <= mid){
		res = min(res, ask(lc, l, mid, ql, qr));
	}
	if(qr > mid){
		res = min(res, ask(rc, mid + 1, r, ql, qr));
	}
	return res;
}


void update(int u, int l, int r, int ql, int qr){
	if(ql <= l && r <= qr){
		minx[u] --;
		tag[u] --;
		return;
	}
	pushdown(u);
	int mid = (l + r) >> 1;
	if(ql <= mid) update(lc, l, mid, ql, qr);
	if(qr > mid) update(rc, mid + 1, r, ql, qr);
	pushup(u);
}

int main(){
	cin.tie(0) -> ios::sync_with_stdio(0);
	cin >> n >> m;

	rep(i, 1, n){
		cin >> seg[i].l >> seg[i].r;
	}

	sort(seg + 1, seg + n + 1, [](node a, node b){
		return a.r < b.r;
	});

	rep(i, 1, m){
		cin >> p[i].pos >> p[i].x;
	}

	sort(p + 1, p + m + 1, [](point a, point b){
		if(a.pos != b.pos) return a.pos < b.pos;
		return a.x < b.x;
	});

	int cnt = 0;
	rep(i, 1, m){
		if(p[i].pos == p[cnt].pos){
			continue;
		}
		else{
			p[++ cnt] = p[i];
		}
	}
	m = cnt;

	build(1, 1, m);

	rep(i, 1, n){
		int ql = lower_bound(p + 1, p + m + 1, seg[i].l, [](point a, int val){
			return a.pos < val;
		}) - p;
		int qr = upper_bound(p + 1, p + m + 1, seg[i].r, [](int val, point a){
			return val < a.pos;
		}) - p - 1;
		if(ask(1, 1, m, ql, qr)){
			ans ++;
			update(1, 1, m, ql, qr);
		}
	}

	cout << ans << '\n';
	return 0;
}
posted @ 2026-04-21 20:46  To_Carpe_Diem  阅读(15)  评论(0)    收藏  举报