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;
}
本文来自一名高中生,作者:To_Carpe_Diem

浙公网安备 33010602011771号