C109 整体二分+树状数组 P7424 [THUPC2017] 天天爱射击
视频链接:C109 整体二分+树状数组 P7424 [THUPC2017] 天天爱射击_哔哩哔哩_bilibili


// 整体二分+树状数组 O(n*logn*logn) #include <iostream> #include <cstring> #include <algorithm> using namespace std; const int N=200005; int n,m,cnt; int l[N],r[N],s[N],ans[N]; struct Q{ //木板: opt=1,[x,y]击穿s次碎掉 //子弹: opt=0,x坐标,y编号 int opt,x,y,s; }q[N<<1],q1[N<<1],q2[N<<1]; struct BIT{ //树状数组 int s[N]; void add(int x,int v){ //点修 for(;x<=N;x+=x&-x) s[x]+=v; } int sum(int x){ //前缀和 int t=0; for(;x;x-=x&-x) t+=s[x]; return t; } }T; void solve(int l,int r,int L,int R){ if(l>r) return; if(L==R){ //统计子弹L击碎的木板数 for(int i=l;i<=r;++i) if(q[i].opt)ans[L]++; return; } int mid=(L+R)>>1,p1=0,p2=0; for(int i=l;i<=r;++i){ //先枚举子弹,后枚举木板 if(!q[i].opt){ //若子弹编号<=mid,则分流到左边,维护左边贡献 if(q[i].y<=mid)q1[++p1]=q[i],T.add(q[i].x,1); else q2[++p2]=q[i]; } else{ int t=T.sum(q[i].y)-T.sum(q[i].x-1); //若木板被击穿子弹数>=s,则分流到左边 if(t>=q[i].s) q1[++p1]=q[i]; else q[i].s-=t,q2[++p2]=q[i]; } } for(int i=1;i<=p1;++i) //清除贡献 if(!q1[i].opt) T.add(q1[i].x,-1); for(int i=1;i<=p1;++i) q[l+i-1]=q1[i]; for(int i=1;i<=p2;++i) q[l+p1+i-1]=q2[i]; solve(l,l+p1-1,L,mid); solve(l+p1,r,mid+1,R); //分治 } int main(){ scanf("%d%d",&n,&m); //n块木板,m个子弹 for(int i=1;i<=n;++i)scanf("%d%d%d",&l[i],&r[i],&s[i]); for(int i=1,x;i<=m;++i)scanf("%d",&x),q[++cnt]={0,x,i};//子弹 for(int i=1;i<=n;++i)q[++cnt]={1,l[i],r[i],s[i]}; //木板 solve(1,cnt,1,m+1); //整体二分,不能击碎的木板分流到m+1区 for(int i=1;i<=m;++i) printf("%d\n",ans[i]); }
 
                    
                     
                    
                 
                    
                 
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号