【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);
}
可持久化并查集
用可持久化数组实现。可持久化数组即可持久化线段树。
本文来自博客园,作者:咕咕坤,转载请注明原文链接:https://www.cnblogs.com/GuguKun/p/14974432.html