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;
}