扫描线
一般扫描线的做法就是想象一根线向某个方向扫过,进入的进入,出去的出去,用一个set维护序列或是结合线段树,当然最恶心的就是加上计算几何
但是落实到这题上就是各种鬼畜乱搞,只能膜大神
省选前做难题的结果是——到处翻题解,程序越改越像
“题意:平面上有n个多边形(凸包和圆)。任意两个多边形AB只有两种关系:(1)A包含B或者B包含A;(2)AB的公共面积为0。每个多边形有一个值x。m个查询。分两种:(1)修改某个多边形的值;(2)从一点s走到另一点t。每次走出一个多边形或者进入一个多边形时,都要抑或上该多边形的值。输出走到t时的值。(由抑或的性质和本题定义可得这个值跟走的路经无关)
思路:首先我们发现,这些多边形构成了一棵树。另外设定义某一点p的值S(p)等于包含该点的所有多边形的值的抑或。那么答案为S(s)^S(t)。对应于那个树上,就是s和t到根的值的抑或和。如果我们建成了这棵树,那么分别维护:(1)修改某点的值;(2)查询某点到根的抑或值。这个可以用树链剖分,之后每个链用树状数组维护。
那么现在的问题来了,这个树怎么建?扫描线。保存多边形的最左最右。排序。按照x升序处理。维护包含当前x的所有多边形。维护的时候将要维护的多边形分成上下两部分。每个多边形的上部的标号就是自己,下部的标号为包含自己的最小多边形。每次假设从当前多边形向上有一条射线,那么第一次交到的就是包含该多边形的多边形(注意我们维护的信息是下部的标号为包含自己的最小多边形)。每次一个多边形不在当前要维护区间时删掉。”
——来自http://www.cnblogs.com/jianglangcaijin/p/4197972.html
很坑!! 有半径为零的圆
#include<cstdio> #include<cstdlib> #include<algorithm> #include<cmath> #include<set> #include<vector> #define V G[p].v #define eps 1e-6 #define inf 1e20 using namespace std; inline int dcmp(double a,double b) { if (fabs(a-b)<eps) return 0; if (a<b) return -1; return 1; } inline void Getchar(char &x) { for (x=getchar();x!='Q' && x!='C' && x!='P';x=getchar()); } inline double sqr(double x){ return x*x; } const int MAXN=300000+5; namespace BIT{ #define lowbit(x) ((x)&-(x)) int c[MAXN]; int maxn; inline void init(int n){ maxn=n; } inline void change(int x,int r){ for (int i=x;i<=maxn;i+=lowbit(i)) c[i]^=r; } inline int sum(int x){ int ret=0; for (int i=x;i;i-=lowbit(i)) ret^=c[i]; return ret; } inline int sum(int l,int r){ if (l>r) return 0; return sum(r)^sum(l-1); } } struct edge{ int u,v; int next; }; edge G[MAXN]; int head[MAXN],inum; inline void add(int u,int v,int p){ G[p].u=u; G[p].v=v; G[p].next=head[u]; head[u]=p; } int size[MAXN],depth[MAXN],fat[MAXN]; int clk,tid[MAXN],top[MAXN]; inline void dfs(int u,int fa){ fat[u]=fa; size[u]=1; depth[u]=depth[fa]+1; for (int p=head[u];p;p=G[p].next) if (V!=fa) dfs(V,u),size[u]+=size[V]; } inline void find(int u,int fa,int z){ tid[u]=++clk; top[u]=z; int maximum=0,son=0; for (int p=head[u];p;p=G[p].next) if (V!=fa && maximum<size[V]) maximum=size[son=V]; if (son) find(son,u,z); for (int p=head[u];p;p=G[p].next) if (V!=fa && V!=son) find(V,u,V); } int val[MAXN]; inline void Change(int u,int r){ BIT::change(tid[u],val[tid[u]]); val[tid[u]]=r; BIT::change(tid[u],r); } inline int Query(int u,int v){ int ret=0; for (;top[u]!=top[v];u=fat[top[u]]) { if (depth[top[u]]<depth[top[v]]) swap(u,v); ret^=BIT::sum(tid[top[u]],tid[u]); } if (depth[u]<depth[v]) swap(u,v); ret^=BIT::sum(tid[v],tid[u]); ret^=val[tid[v]]; return ret; } struct Point{ double x,y; Point(double x=0,double y=0):x(x),y(y) { } }; struct Figure{ int type; Point up[35],down[35]; double x,y,r; int val; int cnt1,cnt2; pair<double,double> read(){ char order; Getchar(order); if (order=='C'){ type=0; scanf("%lf%lf%lf",&x,&y,&r); scanf("%d",&val); return pair<double,double>(x-r,x+r); } type=1; Point tmp[35]; double Min=1e20,Max=-1e20; int n,maxId,minId; scanf("%d",&n); for (int i=0;i<n;i++) { scanf("%lf%lf",&tmp[i].x,&tmp[i].y); if (Min>tmp[i].x) Min=tmp[i].x,minId=i; if (tmp[i].x>Max) Max=tmp[i].x,maxId=i; } if(maxId<minId) { for(int i=minId;i>=maxId;i--) down[cnt2++]=tmp[i]; for(int i=minId;i<n;i++) up[cnt1++]=tmp[i]; for(int i=0;i<=maxId;i++) up[cnt1++]=tmp[i]; } else { for(int i=minId;i<=maxId;i++) up[cnt1++]=tmp[i]; for(int i=minId;i>=0;i--) down[cnt2++]=tmp[i]; for(int i=n-1;i>=maxId;i--) down[cnt2++]=tmp[i]; } scanf("%d",&val); return make_pair(Min,Max); } int find(Point *a,int size,double x) { for(int i=0;i+1<size;i++) if(a[i].x<=x&&x<=a[i+1].x) return i; } double Inter(Point L,Point R,double x) { return L.y+(x-L.x)/(R.x - L.x)*(R.y-L.y); } double Inter(double curx,int dir) { if(type==0) { if(fabs(curx-(x-r))<=1e-3||fabs(curx-(x+r))<=1e-3) { return y; } double tmp=sqr(r)-sqr(x-curx); double d=sqrt(tmp); if(dir) return y+d; return y-d; } if(curx==up[0].x||curx==up[cnt1-1].x) { double Max=-inf,Min=inf; for(int i=0;i<cnt1;i++) if(curx==up[i].x) Max=max(Max,up[i].y); for(int i=0;i<cnt2;i++) if(curx==down[i].x) Min=min(Min,down[i].y); if(!dir) return Min; return Max; } if(dir) { int u=find(up,cnt1,curx); return Inter(up[u],up[u+1],curx); } else { int d=find(down,cnt2,curx); return Inter(down[d],down[d+1],curx); } } }F[100005]; struct event{ double x; int id; int f; bool operator < (const event &B) const{ return dcmp(x,B.x)==0?f<B.f:x<B.x; } }eve[500005]; int tot; struct Query{ int x,y; int type; }Que[100005]; int n,m,ptot; Point P[200005]; double Curx; struct data{ int id,dir,fat; data(int id=0,int dir=0,int fat=0):id(id),dir(dir),fat(fat) { } }; bool operator < (const data &A,const data &B){ if (A.id==B.id) return A.dir<B.dir; double y1=A.id>n?P[A.id-n].y:F[A.id].Inter(Curx,A.dir); double y2=B.id>n?P[B.id-n].y:F[B.id].Inter(Curx,B.dir); return y1<y2; } int Krt; set<data> Set; typedef set<data>::iterator ITER; data U[100005],D[100005]; inline void Init() { sort(eve+1,eve+tot+1); data tmp; for (int i=1;i<=tot;i++) { Curx=eve[i].x; if (eve[i].f==-1) { tmp=data(eve[i].id,1,eve[i].id); Set.insert(tmp); U[eve[i].id]=tmp; ITER it=Set.find(tmp); it++; int belong=it==Set.end()?Krt:it->fat; tmp=data(eve[i].id,0,belong); Set.insert(tmp); D[eve[i].id]=tmp; add(belong,eve[i].id,++inum); } else if (eve[i].f==1) { Set.erase(U[eve[i].id]); Set.erase(D[eve[i].id]); } else if (eve[i].f==0) { tmp=data(eve[i].id,1,0); ITER it=Set.lower_bound(tmp); if(it==Set.end()) add(Krt,eve[i].id,++inum); else add(it->fat,eve[i].id,++inum); } } } int main() { char order; freopen("t.in","r",stdin); freopen("t.out","w",stdout); scanf("%d%d",&n,&m); for (int i=1;i<=n;i++) { pair<double,double> itmp=F[i].read(); eve[++tot].x=itmp.first; eve[tot].id=i; eve[tot].f=-1; eve[++tot].x=itmp.second; eve[tot].id=i; eve[tot].f=1; } for (int i=1;i<=m;i++) { Getchar(order); if (order=='C') { Que[i].type=0; scanf("%d%d",&Que[i].x,&Que[i].y); } else if (order=='Q') { Que[i].type=1; ptot++; scanf("%lf%lf",&P[ptot].x,&P[ptot].y); eve[++tot].x=P[ptot].x; eve[tot].id=ptot+n; eve[tot].f=0; ptot++; scanf("%lf%lf",&P[ptot].x,&P[ptot].y); eve[++tot].x=P[ptot].x; eve[tot].id=ptot+n; eve[tot].f=0; Que[i].x=ptot-1,Que[i].y=ptot; } } Krt=ptot+n+1; Init(); dfs(Krt,0); find(Krt,0,Krt); BIT::init(Krt); for (int i=1;i<=n;i++) Change(i,F[i].val); int lastans=0,_x,_y; for (int i=1;i<=m;i++) { if (Que[i].type==0) { Change(Que[i].x,Que[i].y); } else if (Que[i].type==1) { lastans^=Query(Que[i].x+n,Que[i].y+n); printf("%d\n",lastans); } } return 0; }
我打了一上午的maker,调试了半上午。
最后maker似乎还有多多少少的问题
放弃了他
还是决定放一下
凸包计算几何什么的...
#include<cstdio> #include<cstdlib> #include<algorithm> #include<ctime> #include<cstring> using namespace std; typedef long long ll; struct Point{ int x,y; Point(int x=0,int y=0):x(x),y(y) { } bool operator < (const Point &b) const{ return x<b.x || x==b.x && y<b.y; } }; int s[105]; inline ll Cross(Point p1,Point p2,Point p0) { return ((ll)(p1.x-p0.x))*(p2.y-p0.y)-((ll)(p2.x-p0.x))*(p1.y-p0.y); } int cnt; inline void Qhull(Point *P,Point *hull,int l,int r,Point a,Point b){ int i=l-1,j=r+1,x=l; for (int k=l;k<=r;k++) if (s[k]>s[x] || s[k]==s[x] && P[x]<P[k]) x=k; Point y=P[x]; for (int k=l;k<=r;k++) { s[++i]=Cross(P[k],a,y); if (s[i]>0) swap(P[k],P[i]); else s[i--]=0; } for (int k=r;k>=l;k--) { s[--j]=Cross(P[k],y,b); if (s[j]>0) swap(P[j],P[k]); else s[j++]=0; } if (l<=i) Qhull(P,hull,l,i,a,y); hull[++cnt]=y; if (j<=r) Qhull(P,hull,j,r,y,b); } inline int Pd(Point *p,int n,Point a) { ll tag=Cross(p[n],p[1],a); if (tag==0) return -1; for (int i=1;i<n;i++) { ll tmp=Cross(p[i],p[i+1],a); if (tmp==0) return -1; if ((tmp>0 && tag<0) || (tmp<0 && tag>0)) return 0; } return 1; } inline int random(int x,int y) { return x+rand()*rand()%(y-x+1); } int _N,_M; Point AP[1005][105]; int tot[1005]; inline void Maker(Point *rp,int rn,int xs) { if (xs>=200 || _N>2000) return; int maxx=-1<<30,maxy=-1<<30,minx=1<<30,miny=1<<30,midx,midy; for (int i=1;i<=rn;i++) { maxx=max(maxx,rp[i].x); maxy=max(maxy,rp[i].y); minx=min(minx,rp[i].x); miny=min(miny,rp[i].y); } if ((maxx-minx)<20 || (maxy-miny)<20) return; midx=(maxx+minx)>>1; midy=(maxy+miny)>>1; Point p[5][25]; int n[5]={0}; Point h[25]; int x1,x2,y1,y2; for (int i=1,flag=0;i<=4 && flag<=1;i++) if (rand()%1000) { ++flag; if (i==1){ x1=minx,x2=midx; y1=miny,y2=midy; } else if (i==2){ x1=minx,x2=midx; y1=midy+1,y2=maxy; } else if (i==3){ x1=midx+1,x2=maxx; y1=miny,y2=midy; } else if (i==4){ x1=midx+1,x2=maxx; y1=midy+1,y2=maxy; } // x1=minx,x2=maxx,y1=miny,y2=maxy; // for (int i=1;i<=1;i++){ n[i]=rand()%10+2; int ta=0; for (int j=1;j<=n[i] && !ta;j++) { int c1=0; do { if (++c1==10000) break; p[i][j]=Point(random(x1,x2),random(y1,y2)); if (Pd(rp,rn,p[i][j])!=1) continue; int f=0,tmp; for (int k=1;k<i && !f;k++) if (n[k]) if (Pd(p[k],n[k],p[i][j])!=0) f=1; if (!f) break; }while(1); if (c1==1000) ta=1; } if (!ta) { int x=1; for (int j=1;j<=n[i];j++) if (p[i][j]<p[i][x]) x=j; swap(p[i][1],p[i][x]); cnt=0; memset(s,0,sizeof(s)); h[++cnt]=p[i][1]; Qhull(p[i],h,2,n[i],p[i][1],p[i][1]); if (cnt>2) { _N++; for (int j=1;j<=cnt;j++) { p[i][j]=h[j]; AP[_N][j]=h[j]; } n[i]=tot[_N]=cnt; Maker(p[i],n[i],xs+1); } else n[i]=0; } else n[i]=0; } } int main() { unsigned long long Time=time(0); srand(Time); // freopen("t.in","r",stdin); freopen("t.in","w",stdout); Point P[5],a,b; int maxx=100,maxy=100,minx=-100,miny=-100; P[1]=Point(minx,maxy); P[2]=Point(maxx,maxy); P[3]=Point(maxx,miny); P[4]=Point(minx,miny); Maker(P,4,0); printf("%d %d\n",_N,_M=rand()%10+1); for (int i=1;i<=_N;i++) { printf("P %d",tot[i]); for (int j=1;j<=tot[i];j++) printf(" %.1lf %.1lf",AP[i][j].x/10.0,AP[i][j].y/10.0); printf(" %d\n",rand()*rand()); } while (_M--) { int order=rand()%4+1; if (_N && order==1) { printf("C %d %d\n",rand()%_N+1,rand()*rand()); } else { do { a=Point(random(minx,maxy),random(miny,maxy)); int flag=0,tmp; for (int k=1;k<=_N && !flag;k++) if ((tmp=Pd(AP[k],tot[k],a))==-1) flag=1; if (!flag) break; }while(1); do { b=Point(random(minx,maxy),random(miny,maxy)); int flag=0,tmp; for (int k=1;k<=_N && !flag;k++) if ((tmp=Pd(AP[k],tot[k],a))==-1) flag=1; if (!flag) break; }while(1); printf("Q %.1lf %.1lf %.1lf %.1lf\n",a.x/10.0,a.y/10.0,b.x/10.0,b.y/10.0); } } printf("%u\n",Time); return 0; }