LOJ#2402. 「THUPC 2017」天天爱射击 / Shooting 整体二分+树状数组
我之前一直以为这道题很厉害,没想到就是一个整体二分模板题,就当省选前练练手了.
我们计算每个木棍是被哪个子弹所击碎的,然后这个显然具有单调性.
每一条木棍分别去二分答案的话时间复杂度大概是 $O(n^2 \log n)$ 的.
所以我们就采用整体二分的方式,然后判断的话用一个树状数组来一个区间加法就好了.
然后整体二分的时候要处理好无解的情况.
code:
#include <bits/stdc++.h> #define ll long long #define N 200009 #define setIO(s) freopen(s".in","r",stdin) using namespace std; int n,m; int Ans[N],C[N],ar[N],bu[N]; struct node { int l,r,lim,id; }s[N],ls[N],rs[N]; void update(int x,int v) { for(int i=x;i<N;i+=i&(-i)) C[i]+=v; } int query(int x) { int tmp=0; for(int i=x;i;i-=i&(-i)) tmp+=C[i]; return tmp; } void solve(int l,int r,int L,int R) { if(l==r) { bu[l]=R-L+1; return; } int mid=(l+r)>>1; int tl=0,tr=0,x,y=L-1,z; for(int i=l;i<=mid;++i) update(ar[i],1); for(int i=L;i<=R;++i) { x=query(s[i].r)-query(s[i].l-1); if(x>=s[i].lim) ls[++tl]=s[i]; else s[i].lim-=x,rs[++tr]=s[i]; } for(int i=l;i<=mid;++i) update(ar[i],-1); for(int i=1;i<=tl;++i) s[++y]=ls[i]; for(int i=1;i<=tr;++i) s[++y]=rs[i]; if(tl) solve(l,mid,L,L+tl-1); if(tr) solve(mid+1,r,L+tl,R); } int main() { // setIO("input"); // freopen("input.out","w",stdout); scanf("%d%d",&n,&m); for(int i=1;i<=n;++i) scanf("%d%d%d",&s[i].l,&s[i].r,&s[i].lim),s[i].id=i; for(int i=1;i<=m;++i) scanf("%d",&ar[i]); ar[++m]=ar[1]; solve(1,m+1,1,n); for(int i=1;i<m;++i) printf("%d\n",bu[i]); return 0; }