• 【UOJ553】【UNR #4】己酸集合(分块)


    点此看题面

    • 给定平面上(n)个点,(q)次询问到((0,z_i))距离不超过(r_i)的点数。
    • (nle1.2 imes10^4,qle10^6)

    直线转化

    直接列出判断式:

    [x^2+(y-z_i)^2le r_i^2\ x^2+y^2-2yz_i+z_i^2le r_i^2\ -2yz_i+(x^2+y^2)le r_i^2-z_i^2 ]

    也就是说,对于原图的每一个点我们都可以看成一条解析式为(-2yz_i+(x^2+y^2))的直线,然后一次询问就是要求((z_i,r_i^2-z_i^2))下方的直线数。

    分块+暴枚交点

    我们把序列分成若干块,假设每块大小为(S)

    对于每个块,直接暴枚每对直线求出交点,显然交点个数是(O(S^2))的,然后把它们按照横坐标排序。

    接下来就是依次枚举每个交点,翻转在这个交点上相交的直线的上下顺序,这样就可以维护好横坐标取到每种值时所有直线的上下顺序。

    因此我们把询问离线了,既然已经知道此时直线的上下顺序,直接(lower\_bound)一下就可以查询出下方直线数了。

    复杂度为(O(frac nS(S^2+q)logS^2)),当(S=sqrt q)时取到最优复杂度(O(nsqrt qlog q))

    代码:(O(nsqrt qlogq))

    #include<bits/stdc++.h>
    #define Tp template<typename Ty>
    #define Ts template<typename Ty,typename... Ar>
    #define Reg register
    #define RI Reg int
    #define Con const
    #define CI Con int&
    #define I inline
    #define W while
    #define N 12000
    #define M 1000000
    #define BS 1000
    #define LL long long
    #define DB long double
    #define eps 1e-12
    using namespace std;
    int n,Qt,sz,bl[N+5],ans[M+5];struct Q {int p;LL z,b;I bool operator < (Con Q& o) Con {return z<o.z;}}q[M+5];
    int nw;struct S {LL k,b;I bool operator < (Con S& o) Con {return k*nw+b<o.k*nw+o.b;}}s[N+5];
    namespace FastIO
    {
    	#define FS 100000
    	#define tc() (FA==FB&&(FB=(FA=FI)+fread(FI,1,FS,stdin),FA==FB)?EOF:*FA++)
    	#define pc(c) (FC==FE&&(clear(),0),*FC++=c)
    	#define D isdigit(oc=tc())
    	int ff,OT;char oc,FI[FS],FO[FS],OS[FS],*FA=FI,*FB=FI,*FC=FO,*FE=FO+FS;
    	I void clear() {fwrite(FO,1,FC-FO,stdout),FC=FO;}
    	Tp I void read(Ty& x) {x=0,ff=1;W(!D) ff=oc^'-'?1:-1;W(x=(x<<3)+(x<<1)+(oc&15),D);x*=ff;}
    	Ts I void read(Ty& x,Ar&... y) {read(x),read(y...);}
    	Tp I void writeln(Ty x) {W(OS[++OT]=x%10+48,x/=10);W(OT) pc(OS[OT--]);pc('
    ');}
    }using namespace FastIO;
    struct P {int a,b;DB x,y;I bool operator < (Con P& o) Con {return fabs(x-o.x)>eps?x<o.x:y<o.y;}}p[BS*BS+5];
    int rk[BS+5],vis[BS+5],St[BS+5];I void Solve(S *s,CI n)
    {
    	#define X -1987654321//乱取一个极小点,防止初始情况下直线相交
    	RI i,j,ct=0;DB x;for(nw=X,sort(s+1,s+n+1),i=1;i<=n;++i) for(rk[i]=i,j=i+1;j<=n;++j)//枚举每对直线求交点
    		s[i].k^s[j].k&&(x=1.0L*(s[j].b-s[i].b)/(s[i].k-s[j].k),p[++ct]=(P){i,j,x,s[i].k*x+s[i].b},0);//记录下直线编号
    	RI g=1,T=0,Mn,Mx;for(sort(p+1,p+ct+1),i=1;i<=ct;i=j+1) if(p[j=i].x>X)//按横坐标枚举交点
    	{
    		W(g<=Qt&&q[g].z<p[i].x) nw=q[g].z,ans[q[g].p]+=upper_bound(s+1,s+n+1,(S){0,q[g].b})-s-1,++g;//处理此时询问,lower_bound查询
    		#define Mark(x) (!vis[x]&&(Mn=min(Mn,rk[x]),Mx=max(Mx,rk[x]),vis[St[++T]=x]=1))//标记直线x经过交点
    		Mn=n,Mx=1,Mark(p[i].a),Mark(p[i].b);//Mn,Mx分别维护最小最大排名
    		W(j<=ct&&fabs(p[i].x-p[j+1].x)<eps&&fabs(p[i].y-p[j+1].y)<eps) ++j,Mark(p[j].a),Mark(p[j].b);//同一交点上的直线一起处理
    		reverse(s+Mn,s+Mx+1);W(T) rk[St[T]]=Mn+Mx-rk[St[T]],vis[St[T--]]=0;//翻转顺序
    	}
    	W(g<=Qt) nw=q[g].z,ans[q[g].p]+=upper_bound(s+1,s+n+1,(S){0,q[g].b})-s-1,++g;//处理剩余询问
    }
    int main()
    {
    	RI i,x,y;for(read(n,Qt),sz=sqrt(Qt),i=1;i<=n;++i) read(x,y),s[i]=(S){-2*y,1LL*x*x+1LL*y*y},bl[i]=(i-1)/sz+1;//把点转化为直线
    	for(i=1;i<=Qt;++i) read(x,y),q[i]=(Q){i,x,1LL*y*y-1LL*x*x};sort(q+1,q+Qt+1);//把询问转化为点,事先排好序
    	for(i=1;i<=bl[n];++i) Solve(s+(i-1)*sz,min(i*sz,n)-(i-1)*sz);for(i=1;i<=Qt;++i) writeln(ans[i]);return clear(),0;//分别处理每个块
    }
    
    败得义无反顾,弱得一无是处
  • 相关阅读:
    在chrome插件开发中,如何executeScript多个content script文件
    [Silverlight]MVVM+MEF框架Jounce练习(1)
    EF的日期运算
    【silverlight】Silverlight TreeViw默认展开节点
    singleton pattern简单随笔
    Design pattern形象比喻
    C#简单选择排序
    回文算法
    C#插入排序
    Jquery调用存储过程实例
  • 原文地址:https://www.cnblogs.com/chenxiaoran666/p/UOJ553.html
Copyright © 2020-2023  润新知