几何入门合集

Posted suut

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了几何入门合集相关的知识,希望对你有一定的参考价值。

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)。
我们用同样的方法,朝-y方向看xoz平面。 通过把每个人跟点Q的像Q‘相连,我们发现,左右边界并不对应着最左边与最右边的人。而且随着询问点的变化,对应着左右边界的人也在变化。
如果我们暴力的找对应左右边界的人,复杂度为n*q ,不可行。
我们发现,对应着左右边界的人虽然随着询问点变化,但他们都在凸包上(如下图)。

技术图片

更进一步,如果我们将询问点按照x坐标排序,随着询问的x坐标增加,左右边界的人在凸包上的变化是顺时针旋转的。(考虑你从左到右观察一个正前方的凸包)
于是我们就能够通过一个nlogn的凸包预处理然后O(1)地回答每个询问,复杂度为O(q+nlogn)

剩下的是实现”从左到右看凸包时凸包左右边界的顺时针更新“。
首先是写out,in函数(右手法则,向外转就是逆时针),用来逆时针、顺时针遍历凸包上的点。因为极角排序凸包存的点是逆时针的(极角排序的那个角是与y轴的逆时针夹角。),所以out就是++。
先找到凸包的下上顶点,作为初始的左右边界的对应点。
然后根据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
", 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
", x*h);
        }
        rep(i, 1, q)printf("%.20lf
", (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开始。

以上是关于几何入门合集的主要内容,如果未能解决你的问题,请参考以下文章

如果几何着色器处于活动状态,如何将信息从顶点着色器传递到片段着色器?

VS Code中小程序与Vue常用插件合集(前端合集)

推荐net开发cad入门阅读代码片段

超全超香,数据分析与数据挖掘最频繁使用代码合集来了

《JavaCV从入门到实战教程合集》介绍和目录

《JavaCV从入门到实战教程合集》介绍和目录