UOJ #553. 【UNR #4】己酸集合


题面传送门
容易写出表达式:\((y_i-z_i)^2+x_i\leq r_i^2\)
拆开来得到\(-2y_iz_i+x_i^2+y_i^2\leq r_i^2-z_i^2\)
可以将每个点看成\(y=-2y_ix+x_i^2+y_i^2\)的这么一条直线,那么就是要求\((z_i,r_i^2-z_i^2)\)下方的直线条数。
如果离线询问并按照\(x\)坐标排序后,如果我们能维护出到达每一个\(x\)坐标后直线的相对大小关系,那么就可以直接二分求答案。
考虑分块,设块长为\(B\),则对于每一块内,暴力\(AO(B^2)\)求出直线的交点,显然直线只会在这些交点出改变相对大小关系,且显然这两条直线相邻。那么暴力交换就好了。
如果多于\(2\)条直线共点那么可以按照\(k\)排序之后类似冒泡搞。
然后就处理出了到每个询问时对应的直线簇。时间复杂度\(O(\frac{n}{B}((Q+B^2)\log B))\)\(B=\sqrt Q\)的时候取到最优,为\(O(n\sqrt Q\log Q)\)
code:

#include
#define I inline
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
#define abs(x) ((x)>0?(x):-(x))
#define ll long long
#define db double
#define lb long db
#define N (12000+5)
#define M (1000000+5)
#define K (20+5)
#define mod 1000000007
#define Mod (mod-1)
#define eps (1e-9)
#define U unsigned int
#define it iterator
#define Gc() getchar() 
#define Me(x,y) memset(x,y,sizeof(x))
#define Mc(x,y) memcpy(x,y,sizeof(x))
#define d(x,y) (n*(x-1)+(y))
#define R(n) (rand()*rand()%(n)+1)
#define Pc(x) putchar(x)
#define LB lower_bound
#define UB upper_bound
#define PB push_back
using namespace std;
struct IO{
    static const int S=1<<21;
    char buf[S],*p1,*p2;int st[105],Top;
    ~IO(){clear();}
    inline void clear(){fwrite(buf,1,Top,stdout);Top=0;}
    inline void pc(const char c){Top==S&&(clear(),0);buf[Top++]=c;}
    inline char gc(){return p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++;}
    inline IO&operator >> (char&x){while(x=gc(),x==' '||x=='\n'||x=='\r');return *this;}
    templateinline IO&operator >> (T&x){
        x=0;bool f=0;char ch=gc();
        while(ch<'0'||ch>'9'){if(ch=='-') f^=1;ch=gc();}
        while(ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=gc();
        f?x=-x:0;return *this;
    }
    inline IO&operator << (const char c){pc(c);return *this;}
    templateinline IO&operator << (T x){
        if(x<0) pc('-'),x=-x;
        do{st[++st[0]]=x%10,x/=10;}while(x);
        while(st[0]) pc('0'+st[st[0]--]);return *this;
    }
}fin,fout;
int n,Q,k,x,y,Fr,En,R,H,Lh,Ans[M],X[N],Y[N],Id[N],Ph,l,r,mid;
struct Ques{ll x,y;int id;}S[M];I bool C1(Ques x,Ques y){return x.xy.k:x.bL[y.x].k:L[x.y].k>L[y.y].k);}
int main(){
	freopen("1.in","r",stdin);freopen("1.out","w",stdout);
	int i,j,h;fin>>n>>Q;for(i=1;i<=n;i++) fin>>X[i]>>Y[i];for(i=1;i<=Q;i++) fin>>x>>y,S[i]=(Ques){x,1ll*y*y-1ll*x*x,i};
	sort(S+1,S+Q+1,C1);k=sqrt(Q);for(i=0;i<=n/k;i++){
		Fr=max(i*k,1);En=min(i*k+k-1,n);H=Lh=Ph=0;for(j=Fr;j<=En;j++) L[++Lh]=(Line){-2*Y[j],1ll*X[j]*X[j]+1ll*Y[j]*Y[j],j-Fr+1};
		for(j=1;j<=Lh;j++){
			for(h=j+1;h<=Lh;h++) L[j].k^L[h].k&&(P[++Ph]=(Node){(L[h].b-L[j].b)*1.0/(L[j].k-L[h].k),L[j].k>L[h].k?j:h,L[j].k>1,(L[mid].calc(S[j].x)<=S[j].y?l:r)=mid;Ans[S[j].id]+=l;
			//for(h=2;h<=Lh;h++) if(L[h].calc(S[j].x)