计算几何小结

计算几何小结!

零,说在前面

(转载请注明原文地址:http://www.cnblogs.com/LadyLex/p/8379553.html )

这次总结的是计算几何!

根据学长们的观点,计算几何是一类0or100的题目

但是事实上,计算几何题目很考验码力和细节处理能力,以及数学上平几和立体几何那堆东西……

我个人觉得这样的题目是对个人很好的锻炼,虽然我考场上还是只能打暴力罢了2333

那么我们开始总结吧!

一,凸包

这大概是我们的万恶之源了……这里我把之前的凸包总结搬过来

然后续写两句现在的理解

凸包其实是一种最优化的体现,它通过把处理的对象从全集减少到一些“更可能成为最优答案”的点上,从而使我们能更快得到答案

这点尤为体现在DP的斜率优化上

当然,凸包也在数学和几何方面毒瘤着发挥着作用,也有很多巧妙的题目,比如上面那道uoj243破坏导蛋的处理,那个是我的确没有想到的

当然也有关于凸包的很多算法,但是维护凸包的算法只是工具,重要的还是凸包体现的最优化思想

我觉得在我做过的凸包的题里面给我印象最深的就是uoj319分身术了

充分的利用了题目k比较小的条件,维护了子区间的凸包并且合并,从而支持了快速查询

这是我自从联赛前打模拟题(杀蚂蚁等等)以来打过的最考码力的一道题,打完之后的确感觉码力得到提升2333虽然现在还是咸鱼的打不出来

然而如果考出来还是只能打暴力……

二,旋转卡壳

施工ing……

三,半平面交

这玩意其实和高考数学的线性规划是一个东西……

以前的总结正在补……

先写下最近做的题目……

  UOJ#242 破坏蛋糕

    施工ing……

  UOJ#243 破坏导蛋

    题意很简洁,但是很巧妙也很难想

    我自己能想出加起来总共70pts……

    前20pts暴力不用说啦……

    中间有20pts坐标范围很小,我们可以维护每个x坐标y的前缀和,然后对于每次询问暴力查询

    这样的复杂度是$O(n+200^{2}+200m)$的,可以通过那部分数据

    然后后面有一个很多直线平行的部分分,我觉得可以对于每种直线,维护每个点ax+by的值,然后查询……

    这个东西应该可以搞个分块维护下,块内存个排序,整块用二分,散点暴力

    这样加起来是70pts

    后面的我还不会做,正在想……

    我们还是怂题解吧,这个太巧妙了

    我们上面那个维护查询的问题是每一种ax+by都要处理一次,但是我们可以发现对于某两个点,他们只会在特定的(a,b)处相等

    这样,不同的序列只有$O(n^{2})$级别

    然后我们考虑分块跑这个$n^2$,然后维护一个bitset表示合法

    ……操作很辣眼睛,我只能将近看懂jiry的标程

    啊……我把带注释的std存在这……

  1 #include <iostream>
  2 #include <cmath>
  3 #include <cstdio>
  4 #include <algorithm>
  5 #include <cstring>
  6 #include <bitset>
  7 using namespace std;
  8 #define LL long long
  9 
 10 const int size=200;
 11 struct point
 12 {
 13     int x,y;
 14     double getw(int flag=0)
 15     {
 16         if (flag) return atan2(-y,x);
 17         return atan2(y,x);
 18     }
 19     void scan(){scanf("%d%d",&x,&y);}
 20 
 21 }A[51000],B[size+10],f[size+10];
 22 
 23 point operator - (point k1,point k2) {return (point){k1.x-k2.x,k1.y-k2.y};}
 24 int n,N,m,ans[110000],a[size+10],where[size+10],wa,wb;
 25 double w[size+10];
 26 bitset<size+10>an[110010],C[size+10],tot;
 27 struct ask
 28 {
 29     int a,b,where;
 30     LL c;
 31     double w;
 32     void set(point k1,point k2)
 33         {a=k2.y-k1.y,b=-(k2.x-k1.x),c=-((LL)k1.x*a+(LL)k1.y*b),w=atan2(a,b);}
 34 
 35     int pd(point k1){return (LL)k1.x*a+(LL)k1.y*b+c<=0;}
 36 
 37     void rev(){a=-a,b=-b,c=-c,w=atan2(a,b);}
 38 }x[310000];
 39 
 40 int compare(ask k1,ask k2){return k1.w<k2.w;}
 41 
 42 int compare2(int k1,int k2){return w[k1]<w[k2];}
 43 
 44 const double pi=acos(-1);
 45 
 46 int compare3(int k1,int k2)//comp ax+by
 47     {return (LL)B[k1].x*wa+(LL)B[k1].y*wb<(LL)B[k2].x*wa+(LL)B[k2].y*wb;}
 48 
 49 struct atom{int u,v;double w;}y[110000];
 50 
 51 int len;
 52 
 53 LL k1xk2(point k1,point k2){return (LL)k1.x*k2.y-(LL)k1.y*k2.x;}
 54 
 55 int compare4(const atom &k1,const atom &k2){return k1.w<k2.w;}
 56 
 57 int check(atom k1,atom k2)//两向量平行
 58 {
 59     point a=B[k1.v]-B[k1.u],b=B[k2.v]-B[k2.u];
 60     return k1xk2(a,b)==0&&(LL)a.x*b.x>=0&&(LL)a.y*b.y>=0;
 61 }
 62 
 63 int check(point k1,point k2)//相当于上面的comp3,比较了ax+by
 64     {return (LL)k1.x*wa+(LL)k1.y*wb<(LL)k2.x*wa+(LL)k2.y*wb;}
 65 
 66 void gopre(int k)//由于a和b的更改带来的顺序更改
 67 {
 68     while ( where[k]>1 &&check( B[k],B[ a[where[k]-1] ]  ))
 69     {
 70         int k1=where[k],k2=a[k1-1];
 71         swap(a[k1],a[k1-1]);
 72         swap(f[k1],f[k1-1]);
 73         C[k1-1][k]=1; C[k1-1][k2]=0;
 74         where[k]--; where[k2]++;
 75     }
 76 }
 77 void getw(int k1)
 78 {
 79     int l=1,r=n+1,ans=n+1;
 80     LL aa=x[k1].a,b=x[k1].b,c=x[k1].c;
 81     while (l<r)
 82     {
 83         int mid=(l+r)>>1;
 84         if(aa*f[mid].x+b*f[mid].y+c<=0)l=mid+1;
 85         else ans=mid,r=mid;
 86     }
 87     an[x[k1].id]&=C[ans-1]; 
 88 }
 89 
 90 
 91 int sign,pd[size+10],s[size+10],head;
 92 void insert(int k1)
 93 {
 94     if (pd[k1]!=sign)
 95         pd[k1]=sign,s[++head]=k1;
 96 }
 97 
 98 
 99 void solve(){
100     memset(an,0x00,sizeof an);
101 
102     tot=0; 
103     for(int i=1;i<=n;i++)tot[i]=1;
104     for (int i=1;i<=m/3;i++)an[i]=tot;
105     wa=0; wb=-1;
106 
107     for (int i=1;i<=n;i++)a[i]=i;
108     sort(a+1,a+n+1,compare3);//comp ax+by
109     for (int i=1;i<=n;i++)//记录每个点现在的排名,然后f是排序后的结果
110         where[a[i]]=i,f[i]=B[a[i]];
111     for (int i=1;i<=n;i++)//C是点集前缀和
112         C[i]=C[i-1],C[i][a[i]]=1;
113     
114     len=0;
115     for(int i=1;i<=n;i++)
116         for(int j=1;j<=n;j++)
117             if(i^j)//由j指向i的向量,包括id以及……极角?这个极角是什么操作?
118                 //这大概就是题解中所说的关键点吧……
119                 //如果按照我昨天推的转化式子这玩意是对的,a等于-y,b等于x
120             {
121                 y[++len]=(atom){  j,i,(B[i]-B[j]).getw(1)  };
122                 if(B[i].y==B[j].y)
123                 {
124                     if(B[j].x>B[i].x)y[len].w=-pi;
125                     else y[len].w=0;
126                 }
127             }
128     sort(y+1,y+len+1,compare4);//按极角排序?
129     int pre=1,now=1; y[len+1].w=pi;
130     for (int i=1;i<=len+1;i++)
131     {
132         while(now<=m&&x[now].w<=y[i].w)getw(now++);
133         //还没达到下一个关键点,现在可以更新答案
134         if ( ( i!=len+1  &&  check(y[i],y[i+1])==0    )  || i==len )
135         {//到达关键点(与下一个不平行)
136             wa=-(B[y[i].v].y-B[y[i].u].y);
137             wb=B[y[i].v].x-B[y[i].u].x;
138             //
139             point pre1=(point){wa,wb};
140             if(i==len)wb--;//进行一些偏移
141 
142             else 
143                 wa-=B[y[i+1].v].y-B[y[i+1].u].y,
144                 wb+=B[y[i+1].v].x-B[y[i+1].u].x;
145             if(k1xk2(pre1,(point){wa,wb})==0)//共线?刚才不是判了么?
146                 wa=pre1.y,wb=-pre1.x;
147 
148             head=0;sign++; 
149             for (int j=pre;j<=i;j++)
150                 insert(where[y[j].u]),insert(where[y[j].v]);
151             //插入这段时间内新的点
152             sort(s+1,s+head+1);
153             for (int j=1;j<=head;j++)//进行交换
154                 gopre(a[s[j]]);
155             pre=i+1;
156         }
157     }
158     for (int i=1;i<=m/3;i++) ans[i]+=an[i].count();
159 }
160 int main(){
161 
162 
163 
164     scanf("%d%d",&N,&m); 
165     for (int i=1;i<=N;i++) A[i].scan();
166     for (int i=1;i<=m;i++){
167         point k1,k2,k3; k1.scan(); k2.scan(); k3.scan();
168         x[i*3-2].set(k1,k2);
169         x[i*3-1].set(k2,k3);
170         x[i*3].set(k3,k1);
171         if (x[i*3-2].pd(k3)==0) x[i*3-2].rev();
172         if (x[i*3-1].pd(k1)==0) x[i*3-1].rev();
173         if (x[i*3].pd(k2)==0) x[i*3].rev();
174     }
175 
176 
177 
178     m*=3;
179     for (int i=1;i<=m;i++) x[i].id=(i-1)/3+1;
180     sort(x+1,x+m+1,compare);
181     for (int l=1;l<=N;l+=size)
182     {
183         int r=min(N,l+size-1);
184         n=r-l+1;
185         for(int i=l;i<=r;i++)
186             B[i-l+1]=A[i];
187         solve();
188     }
189     m/=3;
190     for (int i=1;i<=m;i++) printf("%d\n",ans[i]);
191     return 0;
192 }
UOJ#243std

    

四,Simpson积分

施工ing……

五,没做两道题的其他专题

  一,平面图转对偶图

    施工ing……

  二,随机化算法

    1.最小圆覆盖

    施工ing……

  三,三维几何

    施工ing……

六,总结

施工ing……

posted @ 2018-03-06 19:41 LadyLex 阅读(...) 评论(...) 编辑 收藏