【dairylog】学习计算几何

总结:

就是学了一天计算几何妄图写出半平面交然而连直线交点都么学会。

7.5

UVA11971 多边形 Polygon

#include<set>
#include<map>
#include<queue>
#include<cmath>
#include<ctime>
#include<vector>
#include<cstdio>
#include<string>
#include<cstring>
#include<cstdlib>
#include<iomanip>
#include<iostream>
#include<algorithm>
#include<functional>
#define ll long long
using namespace std;

#ifndef DONLINE_JUDGE
char xch, xB[1 << 15], *xS = xB, *xTT = xB;
#define getc() (xS == xTT && (xTT = (xS = xB) + fread(xB, 1, 1 << 15, stdin), xS == xTT) ? 0 : *xS++)
#endif

#ifndef DBUFFETT
#define getc() getchar()
#endif

int rd(){
	int res = 0, fl = 1;
	char c = getchar();
	while(!isdigit(c)){
		if(c == '-') fl = -1;
		c = getchar();
	}
	while(isdigit(c)){
		res = (res << 3) + (res << 1) + c - '0';
		c = getchar();
	}
	return res * fl;
}
int t, n, k, t0;
ll k2, x, y, g;
ll gcd(ll a, ll b){
    return b ? gcd(b , a % b) : a;
}
int main(){
    t = rd();
    
    while(++t0 <= t){
        n = rd(); k = rd();
        y = 1 << k; 
        x = y - k - 1;
        g = gcd(x, y);
        x /= g; 
        y /= g;
        printf("Case #%d: %lld/%lld\n", t0, x, y);
    }
	return 0;
}


半平面交

读入 n 个凸多边形的顶点。

存储将相邻顶点构成的线段(确定的直线)。

将所有直线按极角大小从小到大排序。

维护直线队列,维护直线队列内相邻两直线产生的交点,从而维护半平面交。

每新加入一条直线,对队头队尾元素都有可能又影响,若当前直线与队内直线的交点在半平面交的右边则无影响,左边则有影响。接下来 咕 ···

基本变量——点、线(向量)、双端队列

struct Point{
    double x, y;
    Point(double X = 0, double Y = 0) : x(X), y(Y){}
    Point operator + (const Point &a){
        return Point(x + a.x, y + a.y);
    }
    Point operator - (const Point &a){
        return Point(x - a.x, y - a.y);
    }
    void operator += (const Point &a){
        x += a.x; y += a.y; 
    }
    void operator -= (const Point &a){
        x -= a.x; y -= a.y;
    }
    Point operator * (const double &a)const{
        return Point(x * a, y * a);
    }
    Point operator / (const double &a)const{
        return Point(x / a, y / a);
    }
    void operator *= (const double &a){
        x *= a; y *= a;
    }
    void operator /= (const double a){
        x /= a; y /= a;
    }
}Q[550], M[1100];
struct line{
    Point A, B;
    double C;
    line(Point a, Point b):A(a),B(b){
        C = atan2(B.y, B.x);//sort 
    }
    line(){}
    bool operator < (const line &a)const{
        return C < a.C;//极角排序[-pi, pi]
    }
}P[1100], T[1100];//T是队列
int hd, tl;//头尾指针

基本操作——求两向量叉积、求两直线交点


double Cross_Product(Point A, Point B){
    return A.x * B.y - A.y * B.x;
}
Point GetInter(line A, line B){/
//咕
}

悬线法

悬线法用于求一个矩阵内最大的矩形面积,时空复杂度为 O(n * m)。

所谓悬线法,是说想象一根线悬挂在矩阵上边界或障碍处,保持铅垂,左右移动,然后用这根悬线所能扫到的最大矩形去更新答案。

维护每个点在同一行内向左右能延伸到的最远坐标。记录在 l[i][j]r[i][j] 里。

然后维护每个点向上能延伸到的最靠上的位置,挂悬线,记录在 up[i][j] 。悬线往上挂时要更新当前点的 l[i][j]r[i][j] 值以确保矩形的形状。

例题 P4147 玉蟾宫

代码

#include<set>
#include<map>
#include<queue>
#include<cmath>
#include<ctime>
#include<vector>
#include<cstdio>
#include<string>
#include<cstring>
#include<cstdlib>
#include<iomanip>
#include<iostream>
#include<algorithm>
#include<functional>
#define ll long long
using namespace std;

#ifndef DONLINE_JUDGE
char xch, xB[1 << 15], *xS = xB, *xTT = xB;
#define getc() (xS == xTT && (xTT = (xS = xB) + fread(xB, 1, 1 << 15, stdin), xS == xTT) ? 0 : *xS++)
#endif

#ifndef DBUFFETT
#define getc() getchar()
#endif

int rd(){
	int res = 0, fl = 1;
	char c = getchar();
	while(!isdigit(c)){
		if(c == '-') fl = -1;
		c = getchar();
	}
	while(isdigit(c)){
		res = (res << 3) + (res << 1) + c - '0';
		c = getchar();
	}
	return res * fl;
}
int rdchar(){
    char c = getchar();
    while(!isalpha(c)){
        c = getchar();
    }
    if(c == 'F')    return 1;
    else if(c == 'R')   return 0;
}
int n, m, fld[1010][1010], l[1010][1010], r[1010][1010], up[1010][1010], ans; 
int main(){
    n = rd(); m = rd();
    for(int i = 1; i <= n; ++i){
        for(int j = 1; j <= m; ++j){
            fld[i][j] = rdchar();
        }
    }
    for(int i = 1; i <= n; ++i){
        for(int j = 1; j <= m; ++j){
            if(fld[i][j]){
                l[i][j] = j;
                if(fld[i][j - 1])   l[i][j] = l[i][j - 1]; 
            }
        }
        for(int j = m; j >= 1; --j){
            if(fld[i][j]){
                r[i][j] = j;
                if(fld[i][j + 1])   r[i][j] = r[i][j + 1];
            }
        }
    }
    for(int i = 1; i <= n; ++i){
        for(int j = 1; j <= m; ++j){
            if(fld[i][j]){
                up[i][j] = 1;
                if(fld[i - 1][j]){
                    l[i][j] = max(l[i][j], l[i - 1][j]);
                    r[i][j] = min(r[i][j], r[i - 1][j]);
                    up[i][j] += up[i - 1][j];
                }
            }
            ans = max(ans, (r[i][j] - l[i][j] + 1) * up[i][j]);
        }
    }
    printf("%d\n", ans * 3);
	return 0;
}


单调栈

用于维护下底边在同一高度的矩形。

维护栈内矩形高度递增。

精髓操作是替换矩形以排除无用的矩形边角料。

(见李煜东

借助单调性处理问题的思想在于及时排除不可能的选项,保持策略集合的高度有效性和秩序性,从而为我们做出决策提供更多的条件和方法。

例题 P4147 玉蟾宫

这个题首先要枚举行,然后每一行都做一次单调栈。应该还能优化。

代码

#include<set>
#include<map>
#include<queue>
#include<cmath>
#include<ctime>
#include<vector>
#include<cstdio>
#include<string>
#include<cstring>
#include<cstdlib>
#include<iomanip>
#include<iostream>
#include<algorithm>
#include<functional>
#define ll long long
using namespace std;

#ifndef DONLINE_JUDGE
char xch, xB[1 << 15], *xS = xB, *xTT = xB;
#define getc() (xS == xTT && (xTT = (xS = xB) + fread(xB, 1, 1 << 15, stdin), xS == xTT) ? 0 : *xS++)
#endif

#ifndef DBUFFETT
#define getc() getchar()
#endif

int rd(){
	int res = 0, fl = 1;
	char c = getchar();
	while(!isdigit(c)){
		if(c == '-') fl = -1;
		c = getchar();
	}
	while(isdigit(c)){
		res = (res << 3) + (res << 1) + c - '0';
		c = getchar();
	}
	return res * fl;
}
int rdchar(){
    char c = getchar();
    while(!isalpha(c)){
        c = getchar();
    }
    if(c == 'F')    return 1;
    else if(c == 'R')   return 0;
}
int n, m, fld[1010][1010], ans;
int stk[1010], top, height[1010], w[1010]; 
int main(){
//    freopen("P4147_7.in", "r", stdin);
    n = rd(); m = rd();
    for(int i = 1; i <= n; ++i){
        for(int j = 1; j <= m; ++j){
            fld[i][j] = rdchar();
        }
    }
    for(int i = 1; i <= n; ++i){
        for(int j = 1; j <= m; ++j){
            if(fld[i][j]){
                height[j] ++;
            }
            else height[j] = 0;
        }
        top = 0;
        for(int j = 1; j <= m + 1; ++j){
            int width = 0;
            while(top > 0 && stk[top] >= height[j]){
                width += w[top];
                ans = max(ans, width * stk[top--]);
            }
            stk[++top] = height[j];
            w[top] = width + 1;
        }
        
    }
    printf("%d\n", ans * 3);
	return 0;
}


可持久化线段树1

多棵树,多个根,每棵树可沿用之前的树的结点。

例题 P3919 【模板】可持久化线段树 1(可持久化数组)

如下主函数

int main(){
    n = rd(); m = rd();
    for(int i = 1; i <= n; ++i) w[i] = rd();
    build(root[0], 1, n);
    for(int i = 1; i <= m; ++i){
        v = rd(); op = rd();
        if(op == 1){
            loc = rd(); value = rd();//访问版本v的第loc个位置,修改其值为value
            updata(root[i], root[v], 1, n, loc, value);
        }
        else{
            loc = rd();//询问版本v的第loc个位置的值
            root[i] = root[v];//完全复制版本v
            printf("%d\n", query(root[i], 1, n, loc));
        }
    } 
	return 0;
}

递归建第一颗树


int n, m, loc, value, v, op;
int w[1000010], cnt, root[1000010];
struct Node{
    int l, r, val, ls, rs;
}t[100000010];
void build(int &nownode, int l, int r){
    if(r < l)   return;
    nownode = ++cnt;
    t[nownode].l = l; t[nownode].r = r;
    if(l == r){
        t[nownode].val = w[l];
        return;
    }
    int M = (l + r) >> 1;
    build(t[nownode].ls, l, M);
    build(t[nownode].rs, M + 1, r);
}

总结点数量为 O(?)。

核心部分——树的复制与结点的新建


void updata(int &newnode, int nodev, int l, int r, int location, int val){
    newnode = ++cnt; t[newnode] = t[nodev];
    if(l == r){//新建一个结点
        t[newnode].val = val;
        return;
    }
    int mid = (l + r) >> 1;
    if(location <= mid) updata(t[newnode].ls, t[nodev].ls, l, mid, location, val);
    else updata(t[newnode].rs, t[nodev].rs, mid + 1, r, location, val);
}

单点查询


int query(int &nownode, int l, int r, int location){
    if(l == r)  return t[nownode].val;
    int M = (l + r) >> 1;
    if(location <= M)   return query(t[nownode].ls, l, M, location);
    else return query(t[nownode].rs, M + 1, r, location);
}

可持久化并查集

用可持久化数组实现。可持久化数组即可持久化线段树。

posted @ 2021-07-05 21:13  咕咕坤  阅读(31)  评论(0编辑  收藏  举报