bzoj 2961

根据“点在圆内”关系,列出点P(x0,y0)在圆C(x,y)内的关系:

(x-x0)^2+(y-y0)^2 <= x^2+y^2

化简得:

2*x0*x+2*y0*y >= x0^2+y0^2

然后我们就可以把一个点当成一条线,一个圆当成一个点,通过上面的表达式来转换,这样“点在圆内”的关系就转化成了“点在半平面内”的关系。这样原问题就转化成了不断的加点,然后询问是否所有点都在某个半平面中。

这个东西因为“某一个点在不在半平面中”对”所有点都在半平面中“的答案贡献独立(前者拥有一票否决权),又没有强制在线,所以可以使用对时间分治的思想,以多一个log的复杂度将”边加点边询问问题“变成”先把所有点都加进去,再询问问题“,而后者可以在O(nlogn)时间复杂度内搞定,所以可以在O(nloglog)的时间复杂度内解决。

这道题开始看错题的限制了,题目中限制的是圆心坐标的范围,没有限制询问点坐标的范围,所以就挂了。

  1 /**************************************************************
  2     Problem: 2961
  3     User: idy002
  4     Language: C++
  5     Result: Accepted
  6     Time:6708 ms
  7     Memory:96872 kb
  8 ****************************************************************/
  9
 10 #include <cstdio>
 11 #include <cmath>
 12 #include <vector>
 13 #include <algorithm>
 14 #define N 500010
 15 #define eps 1e-10
 16 using namespace std;
 17
 18 int sg( double x ) { return (x>-eps)-(x<eps); }
 19 struct Vector {
 20     double x, y;
 21     void read() {
 22         scanf( "%lf%lf", &x, &y );
 23     }
 24     Vector(){}
 25     Vector( double x, double y ):x(x),y(y){}
 26     Vector operator+( const Vector &b ) const { return Vector(x+b.x,y+b.y); }
 27     Vector operator-( const Vector &b ) const { return Vector(x-b.x,y-b.y); }
 28     Vector operator*( double b ) const { return Vector(x*b,y*b); }
 29     Vector operator/( double b ) const { return Vector(x/b,y/b); }
 30     double operator^( const Vector &b ) const { return x*b.y-y*b.x; }
 31     double operator&( const Vector &b ) const { return x*b.x+y*b.y; }
 32     double ang() { return atan2l(y,x); }
 33     bool operator<( const Vector &b ) const {
 34         return sg(x-b.x)<0 || (sg(x-b.x)==0 && sg(y-b.y)<0);
 35     }
 36 };
 37 typedef Vector Point;
 38 struct Line {
 39     Point p;
 40     Vector u;
 41     double ang;
 42     int id;
 43     bool ok;
 44     void read( int id ) {
 45         double x, y;
 46         double a, b, c;
 47         scanf( "%lf%lf", &x, &y );
 48         a=x+x, b=y+y;
 49         c=x*x+y*y;
 50
 51         if( sg(a)==0 && sg(b)==0 ) {
 52             p.x = p.y = 0.0;
 53             u.x = 1.0;
 54             u.y = 0.0;
 55         } else {
 56             if( sg(a)!=0 )
 57                 p.x = c/a, p.y = 0.0;
 58             else
 59                 p.x = 0.0, p.y = c/b;
 60             u.x = -b, u.y = a;
 61             if( sg(u^(Point(0.0,0.0)-p))>=0 )
 62                 u.x=-u.x, u.y=-u.y;
 63         }
 64
 65         ok = true;
 66         this->id = id;
 67         ang = u.ang();
 68     }
 69 };
 70 struct Job {
 71     int opt;
 72     Point pt;
 73     Line ln;
 74     void read( int id ) {
 75         scanf( "%d", &opt );
 76         if( opt==0 ) pt.read();
 77         else ln.read(id);
 78     }
 79 };
 80
 81 int n;
 82 Job job[N];
 83 int ans[N];
 84 Point cvx[N];
 85 double lang[N];
 86
 87 bool onleft( Line &l, Point &p ) {  //  <=
 88     return sg( l.u^(p-l.p) ) >= 0;
 89 }
 90 bool onleft( Point &a, Point &b, Point &p ) {   //  <
 91     return sg( (b-a)^(p-a) ) > 0;
 92 }
 93 int convex( vector<Point> &p ) {
 94     sort( p.begin(), p.end() );
 95     int n=p.size();
 96     int m;
 97     cvx[m=0] = p[0];
 98     for( int i=1; i<n; i++ ) {
 99         while( m>0 && !onleft(cvx[m-1],cvx[m],p[i]) ) m--;
100         cvx[++m] = p[i];
101     }
102     int k=m;
103     for( int i=n-2; i>=0; i-- ) {
104         while( m>k && !onleft(cvx[m-1],cvx[m],p[i]) ) m--;
105         cvx[++m] = p[i];
106     }
107     return m;   //  n>=2
108 }
109 void binary( int lf, int rg, vector<Point> &vp, vector<Line> &vn ) {
110     if( lf==rg ) {
111         if( job[lf].opt==0 )
112             vp.push_back( job[lf].pt );
113         else
114             vn.push_back( job[lf].ln );
115         return;
116     }
117     vector<Point> lvp;
118     vector<Line> rvn;
119     int mid=(lf+rg)>>1;
120     binary( lf, mid, lvp, vn );
121     binary( mid+1, rg, vp, rvn );
122     //--
123     Point kpt;
124     if( lvp.empty() || rvn.empty() ) {
125         //  do nothing
126     } else if( lvp.size()==1 ) {
127         for( int t=0; t<rvn.size(); t++ ) {
128             if( !rvn[t].ok ) continue;
129             if( !onleft(rvn[t],lvp[0]) )
130                 rvn[t].ok = false;
131         }
132     } else {
133         int n = convex( lvp );
134         for( int t=0; t<n; t++ )
135             lang[t] = (cvx[(t+1==n?0:t+1)]-cvx[t]).ang();
136         int vid = 0;
137         for( int t=0; t<n; t++ )
138             if( lang[t]>lang[(t+1==n?0:t+1)] ) {
139                 vid = (t+1==n?0:t+1);
140                 break;
141             }
142         rotate( cvx, cvx+vid, cvx+n );
143         rotate( lang, lang+vid, lang+n );
144         for( int t=0; t<rvn.size(); t++ ) {
145             if( !rvn[t].ok ) continue;
146             int tt;
147             if( rvn[t].ang<=lang[0] || rvn[t].ang>=lang[n-1] ) {
148                 tt = 0;
149             } else {
150                 int lf=1, rg=n-1;
151                 while( lf<rg ) {
152                     int mid=(lf+rg)>>1;
153                     if( lang[mid]>rvn[t].ang ) {
154                         rg = mid;
155                     } else {
156                         lf = mid+1;
157                     }
158                 }
159                 tt = lf;
160             }
161             int pt = tt==0?n-1:tt-1;
162             int nt = tt==n-1?0:tt+1;
163             if( !onleft(rvn[t],cvx[tt])
164               ||!onleft(rvn[t],cvx[pt])
165               ||!onleft(rvn[t],cvx[nt]) ) {
166                 rvn[t].ok=false;
167             }
168         }
169     }
170     //--
171     for( int t=0; t<lvp.size(); t++ )
172         vp.push_back( lvp[t] );
173     for( int t=0; t<rvn.size(); t++ )
174         vn.push_back( rvn[t] );
175 }
176 int main() {
177     scanf( "%d", &n );
178     bool ok = false;
179     for( int i=1; i<=n; i++ ) {
180         job[i].read(i);
181         job[i].ln.ok = ok;
182         if( job[i].opt==0 ) ok=true;
183     }
184     vector<Line> vn;
185     vector<Point> vp;
186     binary( 1, n, vp, vn );
187     for( int i=1; i<=n; i++ )
188         ans[i] = -1;
189     for( int t=0; t<vn.size(); t++ )
190         ans[vn[t].id] = vn[t].ok;
191     for( int i=1; i<=n; i++ ) {
192         if( ans[i]==-1 ) continue;
193         printf( "%s\n", ans[i] ? "Yes" : "No" );
194     }
195 }

时间: 2024-09-29 22:10:41

bzoj 2961的相关文章

BZOJ 2961 共点圆 CDQ分治+凸包

题目大意:给定平面,多次插入点和圆,每次插入点时询问当前插入的点是否在之前插入的所有圆中并且至少在一个圆中 直接用数据结构维护这些点和圆不是很好写,我们考虑CDQ分治 对于每层分治,我们需要对于[mid+1,r]中的每个点求出[l,mid]中是否所有的圆都覆盖了这个点 设点的坐标为(x0,y0),那么这个点在所有圆内必须满足对于所有的圆心(x,y),(x-x0)^2+(y-y0)^2<=x^2+y^2,即2*x*x0+2*y*y0>=x0^2+y0^2 我们发现上面的式子是一个半平面,斜率为-

BZOJ 1013: [JSOI2008]球形空间产生器sphere

二次联通门 : BZOJ 1013: [JSOI2008]球形空间产生器sphere /* BZOJ 1013: [JSOI2008]球形空间产生器sphere 高斯消元 QAQ SB的我也能终于能秒题了啊 设球心的坐标为(x,y,z...) 那么就可以列n+1个方程,化化式子高斯消元即可 */ #include <cstdio> #include <iostream> #include <cstring> #define rg register #define Max

bzoj 3309 DZY Loves Math - 莫比乌斯反演 - 线性筛

对于正整数n,定义f(n)为n所含质因子的最大幂指数.例如f(1960)=f(2^3 * 5^1 * 7^2)=3, f(10007)=1, f(1)=0. 给定正整数a,b,求sigma(sigma(f(gcd(i,j)))) (i=1..a, j=1..b). Input 第一行一个数T,表示询问数. 接下来T行,每行两个数a,b,表示一个询问. Output 对于每一个询问,输出一行一个非负整数作为回答. Sample Input 4 7558588 9653114 6514903 445

【BZOJ】[HNOI2009]有趣的数列

[算法]Catalan数 [题解] 学了卡特兰数就会啦>_<! 因为奇偶各自递增,所以确定了奇偶各自的数字后排列唯一. 那么就是给2n个数分奇偶了,是不是有点像入栈出栈序呢. 将做偶数标为-1,做奇数标为+1,显然当偶数多于奇数时不合法,因为它压不住后面的奇数. 然后其实这种题目,打表就可知啦--QAQ 然后问题就是求1/(n+1)*C(2n,n)%p了,p不一定是素数. 参考bzoj礼物的解法. 看到网上清一色的素数筛+分解质因数解法,不解了好久,感觉写了假的礼物-- 后来觉得礼物的做法才比

洛谷 P2709 BZOJ 3781 小B的询问

题目描述 小B有一个序列,包含N个1~K之间的整数.他一共有M个询问,每个询问给定一个区间[L..R],求Sigma(c(i)^2)的值,其中i的值从1到K,其中c(i)表示数字i在[L..R]中的重复次数.小B请你帮助他回答询问. 输入输出格式 输入格式: 第一行,三个整数N.M.K. 第二行,N个整数,表示小B的序列. 接下来的M行,每行两个整数L.R. 输出格式: M行,每行一个整数,其中第i行的整数表示第i个询问的答案. 输入输出样例 输入样例#1: 6 4 3 1 3 2 1 1 3

BZOJ 1012: [JSOI2008]最大数maxnumber(线段树)

012: [JSOI2008]最大数maxnumber Time Limit: 3 Sec  Memory Limit: 162 MB Description 现在请求你维护一个数列,要求提供以下两种操作:1. 查询操作.语法:Q L 功能:查询当前数列中末尾L个数中的最大的数,并输出这个数的值.限制:L不超过当前数列的长度.2. 插入操作.语法:A n 功能:将n加上t,其中t是最近一次查询操作的答案(如果还未执行过查询操作,则t=0),并将所得结果对一个固定的常数D取模,将所得答案插入到数列

【BZOJ】【1016】【JSOI2008】最小生成树计数

Kruskal/并查集+枚举 唉我还是too naive,orz Hzwer 一开始我是想:最小生成树删掉一条边,再加上一条边仍是最小生成树,那么这两条边权值必须相等,但我也可以去掉两条权值为1和3的,再加上权值为2和2的,不也满足题意吗?事实上,如果这样的话……最小生成树应该是1和2,而不是1和3或2和2!!! 所以呢?所以对于一个图来说,最小生成树有几条边权为多少的边,都是固定的!所以我们可以做一遍Kruskal找出这些边权,以及每种边权出现的次数.然后,对于每种边权,比方说出现了$v_i$

【BZOJ】【2844】albus就是要第一个出场

高斯消元解XOR方程组 srO  ZYF  Orz 膜拜ZYF…… http://www.cnblogs.com/zyfzyf/p/4232100.html 1 /************************************************************** 2 Problem: 2844 3 User: Tunix 4 Language: C++ 5 Result: Accepted 6 Time:252 ms 7 Memory:2052 kb 8 *******

[BZOJ 1066] [SCOI2007] 蜥蜴 【最大流】

题目链接:BZOJ - 1066 题目分析 题目限制了高度为 x 的石柱最多可以有 x 只蜥蜴从上面跳起,那么就可以用网络流中的边的容量来限制.我们把每个石柱看作一个点,每个点拆成 i1, i2,从 i1 到 i2 连一条边,容量为这个石柱 i 的高度,即跳跃次数限制.来到这个石柱就是向 i1 连边,从这个石柱跳起就是从 i2 向外连边,这样只要从石柱 i 跳起就一定会消耗 i1 到 i2 的边的容量.如果 i 有蜥蜴,就从 S 到 i1 连一条容量为 1 的边,如果从石柱 i 能跳出边界,就从