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

  

posted @ 2020-06-11 08:37  EM-LGH  阅读(148)  评论(0编辑  收藏  举报