(轉載請註明原文地址:http://www.cnblogs.com/LadyLex/p/8379553.html )html
此次總結的是計算幾何!ios
根據學長們的觀點,計算幾何是一類0or100的題目算法
可是事實上,計算幾何題目很考驗碼力和細節處理能力,以及數學上平幾和立體幾何那堆東西……ide
我我的以爲這樣的題目是對我的很好的鍛鍊,雖然我考場上仍是隻能打暴力罷了2333工具
那麼咱們開始總結吧!優化
這大概是咱們的萬惡之源了……這裏我把以前的凸包總結搬過來atom
而後續寫兩句如今的理解spa
凸包實際上是一種最優化的體現,它經過把處理的對象從全集減小到一些「更可能成爲最優答案」的點上,從而使咱們能更快獲得答案code
這點尤其體如今DP的斜率優化上htm
固然,凸包也在數學和幾何方面毒瘤着發揮着做用,也有不少巧妙的題目,好比上面那道uoj243破壞導蛋的處理,那個是個人確沒有想到的
固然也有關於凸包的不少算法,可是維護凸包的算法只是工具,重要的仍是凸包體現的最優化思想
我以爲在我作過的凸包的題裏面給我印象最深的就是uoj319分身術了
充分的利用了題目k比較小的條件,維護了子區間的凸包而且合併,從而支持了快速查詢
這是我自從聯賽前打模擬題(殺螞蟻等等)以來打過的最考碼力的一道題,打完以後的確感受碼力獲得提高2333雖然如今仍是鹹魚的打不出來
然而若是考出來仍是隻能打暴力……
施工ing……
這玩意其實和高考數學的線性規劃是一個東西……
之前的總結正在補……
先寫下最近作的題目……
施工ing……
題意很簡潔,可是很巧妙也很難想
我本身能想出加起來總共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 }
施工ing……
施工ing……
施工ing……
施工ing……
施工ing……