P4215踩气球题解

题意:有 \(n\) 个盒子和 \(m\) 个熊孩子,每个熊孩子对应一个区间,盒子里有气球,每次踩爆一个盒子中的一个气球,若某个熊孩子对应的区间内气球全部被踩爆,则该熊孩子会很开心。求每次踩气球后开心的熊孩子个数,强制在线。

首先我没有想到怎么离线

看到区间, 首先我们想到线段树。由于只需要考虑空的盒子,那么我们可以用线段树记录线段上空盒子的数量,每次盒子清空才进行修改。

熊孩子怎么处理呢?

答案是:继续上树!

没错,因为熊孩子也有对应区间,我们也可以考虑用线段树去存每个熊孩子。怎么存呢?我们可以考虑把每个熊孩子对应的区间拆成一个个线段树上的区间,然后用vector去存每个区间对应的熊孩子,再用一个 \(cnt\) 数组去存每个熊孩子对应的区间数量。这样,当一个树上的区间内盒子被清空的同时,就将该区间的所有熊孩子弹出,同时将每个熊孩子对应区间数量减一。如果某个熊孩子对应的 \(cnt\) 减为 \(0\),则答案增加一。

至于空间复杂度,由于每个熊孩子对应的长度为 \(l\) 的区间最多被拆成 \(log(l)\) 段,则最多占用 \(mlog(m)\) 的空间;

至于时间复杂度,由于每个线段最多被弹出一次,所以时间最多也为 \(mlog(m)\)

目前最优解第一>w<

(当然也可能是提交的太少了,毕竟我太菜了qwq)

Code:

#include<bits/stdc++.h>
#define ll long long
#define ls tr<<1
#define rs tr<<1|1
using namespace std;
const int N = 1e5+100;

inline int read(){
	int x = 0; char ch = getchar();
	while(ch<'0' || ch>'9'){
		ch = getchar();
	}
	while(ch>='0'&&ch<='9'){
		x = x*10+ch-48; 
		ch = getchar();
	}
	return x;
}

int ans;
//—————————————————————— 
int cnt[N];
vector<int> tree[N<<2];
int sum[N<<2];
void push_up(int tr){
	sum[tr] = sum[ls]+sum[rs];
}
void change_boy(int tr, int L, int R, int lq, int rq, int id){
	if(lq == L && rq == R){
		tree[tr].push_back(id);
		cnt[id]++;
		return;//恰好能放进区间内,则将该段压入该区间。
	}
	int mid = (L+R)>>1;
	if(lq<=mid){
		change_boy(ls, L, mid, lq, min(mid, rq), id);
	}
	if(rq>mid){
		change_boy(rs, mid+1, R, max(mid+1, lq), rq, id);
	} 
	
}

void pop(int tr){
	if(tree[tr].size()){
		for(int i = 0; i<tree[tr].size(); i++){
			cnt[tree[tr][i]]--;
			if(cnt[tree[tr][i]] == 0){
				ans++;
			}
		}
		while(tree[tr].size()){
			tree[tr].pop_back();
		}
	}
}
void change_balloon(int tr, int L, int R, int pos){
	if(L == R){
		sum[tr]++;
		pop(tr);
		return;
	}
	int mid = (L+R)>>1;
	if(pos<=mid){
		change_balloon(ls, L, mid, pos);
	}
	else{
		change_balloon(rs, mid+1, R, pos);
	}
	push_up(tr);
	if(sum[tr] == (R-L+1)){//如果区间内全是空盒子,则将区间清空并统计答案。
		pop(tr);
	}
} 
//——————线段树 ↑———————————— 
int n, m;

int bol[N];
int main(){
	n = read(), m = read();
	for(int i = 1; i<=n; i++){
		bol[i] = read();
	}  	
	for(int i = 1; i<=m; i++){
		int l = read(), r = read();
		change_boy(1, 1, n, l, r, i);
	}
	int Q = read();
	int xx;
	for(int i = 1; i<=Q; i++){
		xx = read();
		xx = (xx + ans-1)%n+1;//强制在线~
		bol[xx]--;
		if(!bol[xx]){
			change_balloon(1, 1, n, xx);
		}
		printf("%d\n", ans);
	}
	return 0;
}
posted @ 2023-06-07 10:47  霜木_Atomic  阅读(32)  评论(0编辑  收藏  举报