bzoj3276磁力 两种要求下的最大值:分块or线段树+拓扑

时间:2019-03-25
本文章向大家介绍bzoj3276磁力 两种要求下的最大值:分块or线段树+拓扑,主要包括bzoj3276磁力 两种要求下的最大值:分块or线段树+拓扑使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

进阶指南上的做法是分块的。。

但是线段树搞起来也挺快,将磁石按照距离排序,建立线段树,结点维护区间质量最小值的下标

进行拓扑,每次在可行的范围内在线段树中找到质量最小的下标取出,取出后再将线段树对应的点设置成0

查询时找区间不为0最小值的下标即可

#include<cstdio>
#include<algorithm>
#define N 250010
typedef long long ll;
int n,i,x0,y0,nowp,x,y,r,c,v[N<<2],tmp,h=1,t,q[N];ll nowr;
struct P{int m,p;ll d,r;}a[N];
inline bool cmp(P x,P y){return x.d<y.d;}
inline void read(int&a){
  char c;bool f=0;a=0;
  while(!((((c=getchar())>='0')&&(c<='9'))||(c=='-')));
  if(c!='-')a=c-'0';else f=1;
  while(((c=getchar())>='0')&&(c<='9'))(a*=10)+=c-'0';
  if(f)a=-a;
}
inline ll sqr(ll x){return x*x;}
inline int lower(){
  int l=1,r=n,t=0,mid;
  while(l<=r)if(a[mid=(l+r)>>1].d<=nowr)l=(t=mid)+1;else r=mid-1;
  return t;
}
inline int merge(int x,int y){
  if(!x)return y;
  if(!y)return x;
  return a[x].m<a[y].m?x:y;
}
inline void up(int x){v[x]=merge(v[x<<1],v[x<<1|1]);}
void build(int x,int a,int b){
  if(a==b){v[x]=a;return;}
  int mid=(a+b)>>1;
  build(x<<1,a,mid),build(x<<1|1,mid+1,b),up(x);
}
void change(int x,int a,int b,int c){
  if(a==b){v[x]=0;return;}
  int mid=(a+b)>>1;
  c<=mid?change(x<<1,a,mid,c):change(x<<1|1,mid+1,b,c);
  up(x);
}
void ask(int x,int a,int b){
  if(b<=c){tmp=merge(tmp,v[x]);return;}
  int mid=(a+b)>>1;
  ask(x<<1,a,mid);
  if(c>mid)ask(x<<1|1,mid+1,b);
}
int main(){
  read(x0),read(y0),read(nowp),read(r),read(n),nowr=sqr(r);
  for(i=1;i<=n;i++){
    read(x),read(y),read(a[i].m),read(a[i].p),read(r);
    a[i].d=sqr(x-x0)+sqr(y-y0),a[i].r=sqr(r);
  }
  std::sort(a+1,a+n+1,cmp),build(1,1,n);
  if(c=lower())while(1){
    tmp=0,ask(1,1,n);
    if(!tmp||a[tmp].m>nowp)break;
    change(1,1,n,q[++t]=tmp);
  }
  while(h<=t){
    nowp=a[q[h]].p,nowr=a[q[h++]].r;
    if(c=lower())while(1){
      tmp=0,ask(1,1,n);
      if(!tmp||a[tmp].m>nowp)break;
      change(1,1,n,q[++t]=tmp);
    }
  }
  return printf("%d",t),0;
}