P4215踩气球题解
题意:有
首先我没有想到怎么离线
看到区间, 首先我们想到线段树。由于只需要考虑空的盒子,那么我们可以用线段树记录线段上空盒子的数量,每次盒子清空才进行修改。
熊孩子怎么处理呢?
答案是:继续上树!
没错,因为熊孩子也有对应区间,我们也可以考虑用线段树去存每个熊孩子。怎么存呢?我们可以考虑把每个熊孩子对应的区间拆成一个个线段树上的区间,然后用vector去存每个区间对应的熊孩子,再用一个
至于空间复杂度,由于每个熊孩子对应的长度为
至于时间复杂度,由于每个线段最多被弹出一次,所以时间最多也为
目前最优解第一>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; }