幾何入門合集
阿新 • • 發佈:2019-04-08
using 能夠 tdi ack ast 極角排序 sta end 處理
我們用同樣的方法,朝-y方向看xoz平面。 通過把每個人跟點Q的像Q‘相連,我們發現,左右邊界並不對應著最左邊與最右邊的人。而且隨著詢問點的變化,對應著左右邊界的人也在變化。
如果我們暴力的找對應左右邊界的人,復雜度為n*q ,不可行。
我們發現,對應著左右邊界的人雖然隨著詢問點變化,但他們都在凸包上(如下圖)。
首先是寫out,in函數(右手法則,向外轉就是逆時針),用來逆時針、順時針遍歷凸包上的點。因為極角排序凸包存的點是逆時針的(極角排序的那個角是與y軸的逆時針夾角。),所以out就是++。
先找到凸包的下上頂點,作為初始的左右邊界的對應點。
然後根據x坐標從小到大枚舉詢問點Q。
對於每個Q,不斷順時針更新左邊界對應的人,直到他與Q的連線在他凸包上順時針的下一個人與Q的連線的外面(直觀上顯然正確)。 右邊界同理。
某些編輯器比如codeforces不能混用iostream與stdio
F. Mirror
題意
鏈接
三維幾何鏡像問題:
有n個人在y=0的平面上(及xoz平面)。z=0平面上有一面鏡子(邊平行於坐標軸)。z=a平面上有q個點(保證a大於所有人的z坐標)。 所有人面朝鏡子,且在鏡子和q個點之間(即每個人的z坐標保證0<z<a)。
問對於某個點,讓所有人能夠通過鏡子看到那個點的鏡子的最小面積。
題解
首先考慮鏡面,我們可以通過(初中科學的)鏡面反射原理,關於z=0做出z=a的對稱平面z=-a。問題就變成了n個人看z=-a上的某個點。(下圖綠點是人,紅點是詢問點)
然後觀察,鏡子的高和寬是獨立的。 於是我們分別求它們的最大值即可。
求高比較簡單,我們朝-x方向看yoz平面。通過把每個人跟點Q的像Q‘相連,我們發現離Q’z軸距離最近的人對應著鏡子的下邊界,最遠的人對應著上邊界,通過維護所有人z坐標的max_z&min_z以及相似三角形可以直接求出兩個邊界,復雜度為O(1)。
如果我們暴力的找對應左右邊界的人,復雜度為n*q ,不可行。
我們發現,對應著左右邊界的人雖然隨著詢問點變化,但他們都在凸包上(如下圖)。
更進一步,如果我們將詢問點按照x坐標排序,隨著詢問的x坐標增加,左右邊界的人在凸包上的變化是順時針旋轉的。(考慮你從左到右觀察一個正前方的凸包)
於是我們就能夠通過一個nlogn的凸包預處理然後O(1)地回答每個詢問,復雜度為O(q+nlogn)
剩下的是實現”從左到右看凸包時凸包左右邊界的順時針更新“。
先找到凸包的下上頂點,作為初始的左右邊界的對應點。
然後根據x坐標從小到大枚舉詢問點Q。
對於每個Q,不斷順時針更新左邊界對應的人,直到他與Q的連線在他凸包上順時針的下一個人與Q的連線的外面(直觀上顯然正確)。 右邊界同理。
某些編輯器比如codeforces不能混用iostream與stdio
代碼
#include<cmath> #include<algorithm> #include<iostream> #include<stdio.h> #include<map> #include<string.h> #include<queue> #include<stack> using namespace std; #define debug(x) cerr<<#x<<" = "<<(x)<<endl #define rep(i,j,k) for(int i = (int)j;i <= (int)k;i ++) #define FAST_IO ios_base::sync_with_stdio(false); cin.tie(nullptr) //#define double long long typedef long long ll; typedef double db; const int maxn = 2e5 + 5; const db eps = 1e-7; int n, q, a; long double ans[maxn]; bool eq(double a, double b) { return abs(a - b) <= eps; } struct V { double x, y; V(double a = 0.0, double b = 0.0) :x(a), y(b) {} void sc() { scanf("%lf%lf", &x, &y); } double operator |(V const &o)const { return x * o.y - o.x * y; } bool operator <(V const &o)const { if (eq(x, o.x))return y < o.y; return x < o.x; } V operator -(V const &o)const { return V(x - o.x, y - o.y); } void pr() { printf("%lf %lf\n", x, y); } }st[maxn]; pair<V, int> Q[maxn]; bool cmpr(V const &a, V const &b) { V v1 = a - st[0], v2 = b - st[0]; return (v1 | v2) < -eps; } vector<V> ch; void getCH() { sort(st + 1, st + n, cmpr); ch.push_back(st[0]); rep(i, 1, n-1) { while (ch.size() > 1 && (st[i] - ch.back() | ch.back() - ch[ch.size() - 2]) < eps)ch.pop_back(); ch.push_back(st[i]); } } int out(int x) { return x ? x - 1 : ch.size() - 1; } int in(int x) { return x + 1 == (int)ch.size() ? 0 : x + 1; } double getx(double xs, double z, double xq) { return xs + z / (z + a) * (xq - xs); } int main() { //FAST_IO; int t; cin >> t; while (t--) { cin >> n >> a; rep(i, 0, n - 1)st[i].sc(); db zmn = st[0].y, zmx = st[0].y; rep(i, 0, n - 1) { zmn = min(zmn, st[i].y); zmx = max(zmx, st[i].y); } rep(i, 0, n - 1)st[i].y = a - st[i].y; sort(st, st + n); ch.clear(); getCH(); cin >> q; ll qx = 0, qy = 0; rep(i, 1, q) { Q[i].first.sc(); Q[i].second = i; } sort(Q + 1, Q + 1 + q); int lp = 0, rp = 0; rep(i, 0, ch.size() - 1)ch[i].y = a - ch[i].y; while (ch[in(rp)].y < ch[rp].y)rp = in(rp); while (ch[out(lp)].y > ch[lp].y)lp = out(lp); rep(i, 1, q) { while (true) { int ni = in(lp); if (getx(ch[ni].x, ch[ni].y, Q[i].first.x) < getx(ch[lp].x, ch[lp].y, Q[i].first.x))lp = ni; else break; } while (true) { int ni = in(rp); if (getx(ch[ni].x, ch[ni].y, Q[i].first.x) > getx(ch[rp].x, ch[rp].y, Q[i].first.x))rp = ni; else break; } double x = abs(getx(ch[rp].x, ch[rp].y, Q[i].first.x) - getx(ch[lp].x, ch[lp].y, Q[i].first.x)); double h = getx(0, zmx, Q[i].first.y) - getx(0, zmn, Q[i].first.y); ans[Q[i].second] = (long double)x * h; //printf("%.20lf\n", x*h); } rep(i, 1, q)printf("%.20lf\n", (double)ans[i]); } cin >> n; } /* 1 3 3 -2 1 7 2 3 1 3 2 5 -2 4 8 10 */
心路歷程
當有兩個以上的bug時你就炸了
wa0:FAST_IO codeforces以用就wa
wa1:輸出rep(i,1,q) not rep(i,1,n)//最後才發現
wa2:凸包板子裏面下標從0開始。
幾何入門合集