Loading

几个板子

FHQ Treap

普通平衡树

struct treap {
	int l, r, siz, dat, val;
} tr[N];
int idx, rt;
int get_new(int val) {
	tr[++ idx].val = val;
	tr[idx].dat = rand();
	tr[idx].siz = 1;
	return idx;
}
void pushup(int u) {
	tr[u].siz = tr[tr[u].l].siz + tr[tr[u].r].siz + 1;
}
void split(int u, int v, int &x, int &y) {
	if(!u) x = y = 0;
	else {
		if(tr[u].val <= v) x = u, split(tr[x].r, v, tr[x].r, y);
		else y = u, split(tr[y].l, v, x, tr[y].l);
		pushup(u);
	}
}
int merge(int x, int y) {
	if(!x || !y) return x + y;
	if(tr[x].dat < tr[y].dat) {
		tr[x].r = merge(tr[x].r, y);
		pushup(x);
		return x;
	}
	else {
		tr[y].l = merge(x, tr[y].l);
		pushup(y);
		return y;
	}
}
void insert(int val) {
	int x, y, z;
	split(rt, val, x, y);
	z = get_new(val);
	rt = merge(merge(x, z), y);
}
void remove(int val) {
	int x, y, z;
	split(rt, val, x, z);
	split(x, val - 1, x, y);
	y = merge(tr[y].l, tr[y].r);
	rt = merge(merge(x, y), z);
}
int get_rk_by_val(int val) {
	int x, y, res;
	split(rt, val - 1, x, y);
	res = tr[x].siz + 1;
	rt = merge(x, y);
	return res;
}
int get_val_by_rk(int u, int rk) {
	if(rk <= tr[tr[u].l].siz) return get_val_by_rk(tr[u].l, rk);
	else if(rk == tr[tr[u].l].siz + 1) return tr[u].val;
	return get_val_by_rk(tr[u].r, rk - tr[tr[u].l].siz - 1);
}
int get_pre(int val) {
	int x, y, res;
	split(rt, val - 1, x, y);
	res = get_val_by_rk(x, tr[x].siz);
	rt = merge(x, y);
	return res;
}
int get_nxt(int val) {
	int x, y, res;
	split(rt, val, x, y);
	res = get_val_by_rk(y, 1);
	rt = merge(x, y);
	return res;
}

文艺平衡树

struct Treap {
	int l, r, val, dat, siz, tag;
} tr[N];
int idx, rt;
void pushup(int u) {
	tr[u].siz = tr[tr[u].l].siz + tr[tr[u].r].siz + 1;
}
void pushdown(int u) {
	if(!tr[u].tag) return;
	swap(tr[u].l, tr[u].r);
	tr[tr[u].l].tag ^= 1;
	tr[tr[u].r].tag ^= 1;
	tr[u].tag = 0;
}
int get_new(int val) {
	tr[++ idx].val = val;
	tr[idx].dat = rand();
	tr[idx].siz = 1;
	return idx;
}
void split(int u, int sz, int &x, int &y) {
	if(!u) {
		x = y = 0;
		return;
	}
	pushdown(u);
	if(tr[tr[u].l].siz < sz) {
		x = u;
		split(tr[u].r, sz - tr[tr[u].l].siz - 1, tr[x].r, y);
	}
	else {
		y = u;
		split(tr[u].l, sz, x, tr[y].l);
	}
	pushup(u);
}
int merge(int x, int y) {
	if(!x || !y) return x + y;
	if(tr[x].dat < tr[y].dat) {
		pushdown(y);
		tr[y].l = merge(x, tr[y].l);
		pushup(y);
		return y;
	}
	else {
		pushdown(x);
		tr[x].r = merge(tr[x].r, y);
		pushup(x);
		return x;
	}
}
void reverse(int l, int r) {
	int x, y, z;
	split(rt, r, y, z);
	split(y, l - 1, x, y);
	tr[y].tag ^= 1;
	rt = merge(x, merge(y, z));
}
void output(int u) {
	if(!u) return;
	pushdown(u);
	output(tr[u].l);
	cout << tr[u].val << ' ';
	output(tr[u].r);
}

Treap

struct treap {
	int l, r;
	int val, dat;
	int cnt, siz;
} tr[N];
int idx, rt;
int get_new(int val) {
	tr[++ idx].val = val;
	tr[idx].dat = rand();
	tr[idx].siz = tr[idx].cnt = 1;
	return idx;
}
void pushup(int x) {
	tr[x].siz = tr[tr[x].l].siz + tr[tr[x].r].siz + tr[x].cnt;
}
void zig(int &x) {
	int y = tr[x].l;
	tr[x].l = tr[y].r, tr[y].r = x, x = y;
	pushup(tr[x].r), pushup(x);
}
void zag(int &x) {
	int y = tr[x].r;
	tr[x].r = tr[y].l, tr[y].l = x, x = y;
	pushup(tr[x].l), pushup(x);
}
void insert(int &x, int val) {
	if(x == 0) {
		x = get_new(val);
		return;
	}
	if(val == tr[x].val) {
		tr[x].cnt ++, pushup(x);
		return;
	}
	if(val < tr[x].val) {
		insert(tr[x].l, val);
		if(tr[tr[x].l].dat > tr[x].dat) zig(x);
	}
	else if(val > tr[x].val) {
		insert(tr[x].r, val);
		if(tr[tr[x].r].dat > tr[x].dat) zag(x);
	}
	pushup(x);
}
void remove(int &x, int val) {
	if(x == 0) return;
	if(tr[x].val == val) {
		if(tr[x].cnt > 1) {
			tr[x].cnt --;
			pushup(x);
			return;
		}
		if(tr[x].l || tr[x].r) {
			if(tr[x].r == 0 || tr[tr[x].l].dat > tr[tr[x].r].dat)
				zig(x), remove(tr[x].r, val);
			else
				zag(x), remove(tr[x].l, val);
			pushup(x);
		}
		else x = 0;
		return;
	}	
	if(val < tr[x].val) remove(tr[x].l, val);
	else remove(tr[x].r, val);
	pushup(x);
}
int get_rk_by_val(int x, int val) {
	if(x == 0) return 0;
	if(val == tr[x].val) return tr[tr[x].l].siz + 1;
	if(val < tr[x].val) return get_rk_by_val(tr[x].l, val);
	return tr[tr[x].l].siz + tr[x].cnt + get_rk_by_val(tr[x].r, val);
}
int get_val_by_rk(int x, int rk) {
	if(x == 0) return INF;
	if(tr[tr[x].l].siz >= rk) return get_val_by_rk(tr[x].l, rk);
	if(tr[tr[x].l].siz + tr[x].cnt >= rk) return tr[x].val;
	return get_val_by_rk(tr[x].r, rk - tr[tr[x].l].siz - tr[x].cnt);
}
int get_pre(int x, int val) {
	if(x == 0) return -INF;
	if(val <= tr[x].val) return get_pre(tr[x].l, val);
	return max(tr[x].val, get_pre(tr[x].r, val)); 
}
int get_nxt(int x, int val) {
	if(x == 0) return INF;
	if(val >= tr[x].val) return get_nxt(tr[x].r, val);
	return min(tr[x].val, get_nxt(tr[x].l, val));
}

树状数组

struct BIT {
	int n;
	vector<int> c;
	void init(int N) {
		n = N;
		c.resize(n + 1);
	}
	#define lbt(x) x & -x
	void modify(int x, int v) {
		for(; x <= n; x += lbt(x)) c[x] += v;
	}
	int query(int x) {
		int res = 0;
		for(; x; x -= lbt(x)) res += c[x];
		return res;
	}
} bit;

线段树

区间修区间查

struct Tag {

    bool empty () {
	
    }
    void clear() {
    	
    }
};

struct Info {
	
};

Info operator + (Info lhs, Info rhs) {
	
}

Info operator + (Info lhs, Tag rhs) {
	
}

Tag operator +(Tag lhs, Tag rhs) {
	
}

struct Segment_Tree {
    struct Node {
        int l, r;
        Info val;
        Tag tag;
        void apply(Tag v) {
            val = val + v;
            tag = tag + v;
            return;
        }

        #define l(x) tr[x].l
        #define r(x) tr[x].r
        #define val(x) tr[x].val
        #define tag(x) tr[x].tag
    } tr[N << 2];

    void pushdown(int x) {
        if (tag(x).empty()) {
            return;
        }
        tr[x * 2].apply(tag(x)), tr[x * 2 + 1].apply(tag(x));
        tag(x).clear();
    }

    void build(int l, int r, int x) {
        tr[x] = {l, r};
        tag(x).clear();
        if (l == r) {
            
            return;
        }
        int mid = (l + r) / 2;
        build(l, mid, x * 2), build(mid + 1, r, x * 2 + 1);
        val(x) = val(x * 2) + val(x * 2 + 1);
    }

    void update(int l, int r, int x, Tag v) {
        if (l <= l(x) && r(x) <= r) {
            tr[x].apply(v);
            return;
        }
        pushdown(x);
        int mid = (l(x) + r(x)) / 2;
        if (l <= mid) {
            update(l, r, x * 2, v);
        } 
        if (r > mid) {
            update(l, r, x * 2 + 1, v);
        }
        val(x) = val(x * 2) + val(x * 2 + 1);
    }

    Info query(int l, int r, int x) {
        if (l <= l(x) && r(x) <= r) return val(x);
        pushdown(x);
        int mid = (l(x) + r(x)) / 2;
        if (r <= mid) {
            return query(l, r, x * 2);
        } else if (l > mid) {
            return query(l, r, x * 2 + 1);
        } else {
            return query(l, r, x * 2) + query(l, r, x * 2 + 1);
        }
    }

} SegT;

单调修区间查

struct Tag {
	
    bool empty () {
    	
    }
    void clear() {
    	
    }
};

struct Info {
	
};

Info operator + (Info lhs, Info rhs) {
	
}

Info operator + (Info lhs, Tag rhs) {
	
}

Tag operator +(Tag lhs, Tag rhs) {
	
}

struct Segment_Tree {
    struct Node {
        int l, r;
        Info val;

        #define l(x) tr[x].l
        #define r(x) tr[x].r
        #define val(x) tr[x].val
        #define tag(x) tr[x].tag
    } tr[N << 2];

    void build(int l, int r, int x) {
        tr[x] = {l, r};
        tag(x).clear();
        if (l == r) {
		
            return;
        }
        int mid = (l + r) / 2;
        build(l, mid, x * 2), build(mid + 1, r, x * 2 + 1);
        val(x) = val(x * 2) + val(x * 2 + 1);
    }

    void update(int p, int x, Info v) {
        if (l(x) == r(x)) {
            
            return;
        }
        pushdown(x);
        int mid = (l(x) + r(x)) / 2;
        if (l <= mid) {
            update(l, r, x * 2, v);
        } 
        if (r > mid) {
            update(l, r, x * 2 + 1, v);
        }
        val(x) = val(x * 2) + val(x * 2 + 1);
    }

    Info query(int l, int r, int x) {
        if (l <= l(x) && r(x) <= r) return val(x);
        int mid = (l(x) + r(x)) / 2;
        if (r <= mid) {
            return query(l, r, x * 2);
        } else if (l > mid) {
            return query(l, r, x * 2 + 1);
        } else {
            return query(l, r, x * 2) + query(l, r, x * 2 + 1);
        }
    }

} SegT;

树链剖分

int id[N], top[N], fa[N], dep[N], siz[N], son[N], idx;
int a[N], w[N];
void dfs1(int u, int fath) {
	fa[u] = fath, dep[u] = dep[fath] + 1;
	siz[u] = 1;
	for(int i = h[u]; i; i = nxt[i]) {
		int v = to[i];
		if(v == fath) continue;
		dfs1(v, u);
		siz[u] += siz[v];
		if(siz[v] > siz[son[u]]) son[u] = v;
	}
}
void dfs2(int u, int fst) {
	top[u] = fst, id[u] = ++ idx, a[idx] = w[u];
	if(!son[u]) return;
	dfs2(son[u], fst);
	for(int i = h[u]; i; i = nxt[i]) {
		int v = to[i];
		if(v == son[u] || v == fa[u]) continue;
		dfs2(v, v);
	}
}
int lca(int u, int v) {
    while(top[u] != top[v])
        dep[top[u]] > dep[top[v]] ? u = fa[top[u]] : v = fa[top[v]]; 
    return dep[u] < dep[v] ? u : v;
}

快速幂

int power(int a, int b) {
	int res = 1;
	for(; b; a = (LL)a * a % mod, b >>= 1) if(b & 1) res = res * a % mod; 
	return res;
}

ST表

for(int j = 1; (1 << j) <= n; j ++)
		for(int i = 1; i + (1 << j) - 1 <= n; i ++)
			f[i][j] = max(f[i][j - 1], f[i + (1 << (j - 1))][j - 1]);

dijkstra

void duijkstra() {
	for(int i = 1; i <= n; i ++) dist[i] = INF, st[i] = false;
	priority_queue<PII, vector<PII>, greater<PII> > q;
	dist[s] = 0;
	q.push({0, s});
	while(q.size()) {
		int u = q.top().se;
		q.pop();
		if(st[u]) continue;
		st[u] = true;
		for(int i = h[u]; i; i = nxt[i]) {
			int v = to[i], w = val[i];
			if(dist[v] > dist[u] + w) {
				dist[v] = dist[u] + w;
				q.push({dist[v], v});
			}
		}
	}
}

加边

int h[N], nxt[M << 1], to[M << 1], val[M << 1], cnt;
void add(int u, int v, int w) {
	to[++ cnt] = v, val[cnt] = w, nxt[cnt] = h[u], h[u] = cnt;
}
int h[N], nxt[M << 1], to[M << 1], cnt;
void add(int u, int v) {
	to[++ cnt] = v, nxt[cnt] = h[u], h[u] = cnt;
}

LCA

void dfs(int u, int fath) {
    dep[u] = dep[fath] + 1, fa[u][0] = fath;
    for(int i = 1;i <= __lg(dep[u]);i ++) fa[u][i] = fa[fa[u][i - 1]][i - 1];
    for(int i = h[u]; i; i = nxt[i])
    {
        int v = to[i];
        if(v == fath) continue;
        dfs(v, u);
    }
}
int lca(int u, int v)
{
    if(dep[u] < dep[v]) swap(u, v);
    while(dep[u] > dep[v]) u = fa[u][__lg(dep[u] - dep[v])];
    if(u == v) return u;
    for(int k = __lg(dep[u]); ~k; k --)
        if(fa[u][k] != fa[v][k]) u = fa[u][k], v = fa[v][k];
    return fa[u][0];
}

DSU

struct DSU {
    int N;
    vector<int> fa, siz;
    DSU() {};
    DSU(int n) {
        init(n);
    }
    void init(int n) {
        N = n;
        fa.resize(N + 1);
        siz.resize(N + 1);
        iota(fa.begin(), fa.end(), 0);
        siz.assign(N + 1, 1);
    }
    int find(int x) {
        return fa[x] == x ? x : fa[x] = find(fa[x]);
    }
    bool same(int x, int y) {
        return find(x) == find(y);
    }
    void merge(int x, int y) {
        x = find(x), y = find(y);
        if(same(x, y)) return;
        fa[x] = y;
        siz[y] += siz[x];
    }
};

最小生成树

	sort(e + 1, e + 1 + m);
	ll res = 0;
	for(int i = 1; i <= m; i ++) {
		int u = find(e[i].u), v = find(e[i].v);
		if(u == v) continue;
		res += e[i].w;
		merge(u, v);
	}

Floyd

for(int i = 1; i <= n; i ++) f[i][i] = 0;
	for(int k = 1; k <= n; k ++)
		for(int i = 1; i <= n; i ++)
			for(int j = 1; j <= n; j ++) 
				f[i][j] = min(f[i][j], f[i][k] + f[k][j]);

矩阵快速幂

struct matrix {
	LL c[105][105];
} A;
LL n, k;
matrix operator *(const matrix &a, const matrix &b) {
	matrix c;
	for(int i = 1; i <= n; i ++)
		for(int j = 1; j <= n; j ++) c.c[i][j] = 0;
	for(int i = 1; i <= n; i ++)
		for(int j = 1; j <= n; j ++)
			for(int k = 1; k <= n; k ++)
				c.c[i][j] = (c.c[i][j] + a.c[i][k] * b.c[k][j]) % mod;
	return c;
}
matrix qpow(matrix a, ll b)
{
	matrix res;
	for(int i = 1; i <= n; i ++) res.c[i][i] = 1;
	for(; b; a = a * a, b >>= 1)if(b & 1) res = res * a;
	return res;
}

最大流

template <class Type>
struct Flow {
	int h[N], nxt[M << 1], to[M << 1], cnt;
	int S, T;
	Type val[M << 1];
	int cur[N], d[N];
	void init(int _S, int _T) {
		S = _S, T = _T, cnt = 1;
	}
	void add(int u, int v, Type w) {
		to[++ cnt] = v, val[cnt] = w, nxt[cnt] = h[u], h[u] = cnt;
		to[++ cnt] = u, val[cnt] = 0, nxt[cnt] = h[v], h[v] = cnt;
	}
	bool bfs() {
		memset(d, -1, sizeof d);
		d[S] = 0, cur[S] = h[S];
		queue<int> q;
		q.push(S);
		while(q.size()) {
			int u = q.front();
			q.pop();
			for(int i = h[u]; i; i = nxt[i]) {
				int v = to[i];
				if(d[v] == -1 && val[i]) {
					d[v] = d[u] + 1;
					cur[v] = h[v];
					if(v == T) return true;
					q.push(v);
				}
			}
		}
		return false;
	}
	Type dfs(int u, Type lim) {
		if(u == T) return lim;
		Type flow = 0;
		for(int i = cur[u]; i && flow < lim; i = nxt[i]) {
			cur[u] = i;
			int v = to[i];
			if(d[v] == d[u] + 1 && val[i]) {
				int t = dfs(v, min(val[i], lim - flow));
				if(!t) d[v] = -1;
				flow += t, val[i] -= t, val[i ^ 1] += t;
			}
		}
		return flow;
	}
	Type dinic() {
		Type flow, res = 0;
		while(bfs()) while(flow = dfs(S, INF)) res += flow;
		return res;
	}
};

Modint

template <typename T>  T power(T a, ll b) {
    T c{1}; for (; b; b /= 2, a *= a) if (b & 1) c *= a;
    return c;
}
template <int P> struct MInt {
    int x;
    MInt() : x{} {}
    MInt(ll x_) : x{norm(x_ % getMod())} {}
    static int Mod;
    static int getMod() { return P > 0 ? P : Mod; }
    static void setMod(int Mod_) { Mod = Mod_; }
    int up(int x) const {
        if (x < 0) x += getMod();
        return x;
    }
    int down(int x) const {
        if (x >= getMod()) x -= getMod();
        return x;
    }
    int norm(int x) const {
        return up(down(x));
    }
    int val() const { return x; }
    explicit  operator int() const { return x; }
    MInt operator-() const {
        MInt res; res.x = norm(getMod() - x); return res;
    }
    MInt inv() const {
        assert(x != 0);
        return power(*this, getMod() - 2);
    }
    MInt &operator+=(MInt rhs) & { return x = down(x + rhs.x), *this; }
    MInt &operator-=(MInt rhs) & { return x = up(x - rhs.x), *this; }
    MInt &operator*=(MInt rhs) & { return x = 1ll * x * rhs.x % getMod(), *this; }
    MInt &operator/=(MInt rhs) & { return *this *= rhs.inv(); }
    friend MInt operator+(MInt lhs, MInt rhs) { return lhs += rhs; }
    friend MInt operator-(MInt lhs, MInt rhs) { return lhs -= rhs; }
    friend MInt operator*(MInt lhs, MInt rhs) { return lhs *= rhs; }
    friend MInt operator/(MInt lhs, MInt rhs) { return lhs /= rhs; }
    friend bool operator==(MInt lhs, MInt rhs) { return lhs.val() == rhs.val(); }
    friend  bool operator!=(MInt lhs, MInt rhs) { return lhs.val() != rhs.val(); }
    friend  std::istream &operator>>(std::istream &is, MInt &a) {
        ll x = 0; is >> x, a = MInt(x); return is;
    }
    friend  std::ostream &operator<<(std::ostream &os, const MInt &a) {
        return os << a.val();
    }
};
const int P = 1e9 + 7;
using Z = MInt<P>; 

Comb

Z fac[N], infac[N];
void init(int n) {
	fac[0] = infac[0] = 1;
	for (int i = 1; i <= n; i ++) {
		fac[i] = fac[i - 1] * i;
	}
	infac[n] = (Z)1 / fac[n];
	for (int i = n - 1; i >= 1; i --) {
		infac[i] = infac[i + 1] * (i + 1);
	}
}

Z comb(int a, int b) {
	if (a < 0 || b < 0 || a < b) return 0;
	return fac[a] * infac[a - b] * infac[b];
} 

计算几何

const double eps = 1e-8;
const double pi = acos(-1);

int dcmp(double x) { //精度判断
	if(fabs(x) < eps) return 0;
	if(x < 0) return -1;
	return 1;
}

struct point { //点或向量
	double x, y;
	point(double X = 0, double Y = 0) {
		x = X, y = Y;
	}
};

typedef point Vector;

struct Line {
	point A, B;
	Line(point a = point(), point b = point()) {
		A = a, B = b;
	}
};

struct Segment {
	point A, B;
	Segment(point a = point(), point b = point()) {
		A = a, B = b;
	}
};

struct circle {
	point p; //圆心
	double r;
	circle(point A = point(), double B = 0) {
		p = A, r = B;
	}
};


double len(point a) { //向量长度
	return sqrt(a.x * a.x + a.y * a.y);
}

double dis(point a, point b) { //两点距离
	return len(a - b);
}

point operator + (point a, point b) {
	return point(a.x + b.x, a.y + b.y);
}

point operator - (point a, point b) {
	return point(a.x - b.x, a.y - b.y);
}

point operator * (point a, double k) {
	return point(a.x * k, a.y * k);
}

double dot(point a, point b) { //点积
	return a.x * b.x + a.y * b.y;
}

double cross(point a, point b) { //叉积
	return a.x * b.y - a.y * b.x;
}

double angle(point a, point b) { //两向量夹角
	return acos(dot(a, b) / len(a) / len(b));
}

double polar_angle(point a) { //极角
	return atan2(a.y, a.x);
}

point rotate(point a, double alpha) { //向量旋转
	return point(
		a.x * cos(alpha) - a.y * sin(alpha),
		a.x * sin(alpha) + a.y * cos(alpha)
	);
}

bool parallel(Line l1, Line l2) { // 平行
	return dcmp(cross(l1.B - l1.A, l2.B - l2.A)) == 0;
}

bool same_line(Line l1, Line l2) {
	return parallel(l1, l2) &&
		   dcmp(cross(l2.A - l1.A, l1.B - l1.A)) == 0;
}

bool parallel_not_same(Line l1, Line l2) {
	return parallel(l1, l2) && !same_line(l1, l2);
}

bool p_on_line(point p, point A, point B) { //点在线段AB上
	return dcmp(cross(p - A, p - B)) == 0 &&
		   dcmp(dot(p - A, p - B)) <= 0;
}

double dis_p_seg(point p, point A, point B) { //点到线段距离
	if(dcmp(dot(p - A, B - A)) < 0) return dis(p, A);
	if(dcmp(dot(p - B, A - B)) < 0) return dis(p, B);
	return fabs(cross(A - p, B - p)) / dis(A, B);
}

bool pd_SS(point A, point B, point C, point D) // 线段是否相交
{
	if(max(A.x,B.x)<min(C.x,D.x) ||
	   max(C.x,D.x)<min(A.x,B.x) ||
	   max(A.y,B.y)<min(C.y,D.y) ||
	   max(C.y,D.y)<min(A.y,B.y))
		return false;

	return dcmp(cross(C-A,B-A))
	     * dcmp(cross(D-A,B-A)) <= 0
	    &&
	       dcmp(cross(A-C,D-C))
	     * dcmp(cross(B-C,D-C)) <= 0;
}

double dis_p_line(point p, point A, point B) { //点到直线距离
	return fabs(cross(p - A, p - B)) / len(A - B);
}

point get_line_root(point p, point A, point B) { //投影点
	point v = B - A;
	return A + v * (dot(p - A, v) / dot(v, v));
}

point symmetry_PL(point p, point A, point B) { //关于直线对称
	return p + (get_line_root(p, A, B) - p) * 2;
}

point p_of_intersection(point A, point B, point C, point D) { //直线交点
	point v = B - A;
	point w = D - C;
	double t = cross(C - A, w) / cross(v, w);
	return A + v * t;
}

bool pd_PS(point p, point A, point B) { //点在线段
	return dcmp(cross(p - A, p - B)) == 0 &&
		   dcmp(dot(p - A, p - B)) <= 0;
}

//任意多边形点定位
bool in_polygon(point p, point *a, int n) {
	double sum = 0;
	for(int i = 1; i <= n; i++) {
		if(i == n) sum += angle(a[i] - p, a[1] - p);
		else sum += angle(a[i] - p, a[i + 1] - p);
	}
	return dcmp(sum - 2 * pi) == 0;
}


//凸多边形点定位 O(log n)
int in_polygon2(point p, point *a, int n) {
	if(dcmp(cross(p - a[1], a[2] - a[1])) < 0 ||
	   dcmp(cross(p - a[1], a[n] - a[1])) > 0)
		return 0;
	if(pd_PS(p, a[1], a[2]) ||
	   pd_PS(p, a[n], a[1]))
		return 2;
	int l = 2, r = n;
	while(r - l > 1) {
		int mid = (l + r) >> 1;
		if(dcmp(cross(p - a[1], a[mid] - a[1])) < 0) l = mid;
		else r = mid;
	}

	if(dcmp(cross(p - a[l], a[r] - a[l])) > 0)
		return 0;
	if(pd_PS(p, a[l], a[r]))
		return 2;
	return 1;
}


//点到圆切线
int get_PC(point p, circle c, Line *v) {
	Vector u = c.p - p;
	double d = dis(p, c.p);
	if(dcmp(d - c.r) < 0)
		return 0;
	if(dcmp(d - c.r) == 0) {
		v[0] = Line(p, p + rotate(u, pi / 2));
		return 1;
	}
	double alpha = asin(c.r / d);
	v[0] = Line(p, p + rotate(u, alpha));
	v[1] = Line(p, p + rotate(u, -alpha));
	return 2;
}

//圆上一点
point get_point(circle c, double a) {
	return point(
		c.p.x + cos(a) * c.r,
		c.p.y + sin(a) * c.r
	);
}

//两圆交点
int get_CC(circle c1, circle c2, vector<point>& ans) {

	double d = dis(c1.p, c2.p);
	if(dcmp(d) == 0) {
		if(dcmp(c1.r - c2.r) == 0)
			return -1;
		return 0;
	}
	if(dcmp(c1.r + c2.r - d) < 0)
		return 0;
	if(dcmp(fabs(c1.r - c2.r) - d) > 0)
		return 0;
	double alpha = polar_angle(c2.p - c1.p);
	double beta = acos(
		(c1.r * c1.r + d * d - c2.r * c2.r)
		/ (2 * c1.r * d)
	);

	point p1 = get_point(c1, alpha - beta);
	point p2 = get_point(c1, alpha + beta);

	ans.push_back(p1);

	if(dcmp(dis(p1, p2)) == 0)
		return 1;

	ans.push_back(p2);

	return 2;
}


//多边形面积
double polygon_area(point *a, int n) {
	double ans = 0;
	for(int i = 2; i < n; i++)
		ans += cross(a[i] - a[1], a[i + 1] - a[1]);

	return fabs(ans / 2);
}

vector<point> graham(vector<point> p) { //Graham求凸包
	int n = p.size();
	int id = 0;
	for(int i = 1; i < n; i++) {
		if(p[i].y < p[id].y ||
		  (dcmp(p[i].y - p[id].y) == 0 &&
		   p[i].x < p[id].x))
			id = i;
	}
	swap(p[0], p[id]);
	sort(p.begin() + 1, p.end(), [&](point a, point b) {
		double c = cross(a - p[0], b - p[0]);
		if(dcmp(c) != 0)
			return c > 0; //极角从小到大
		return dis(a, p[0]) < dis(b, p[0]); //距离近的优先
	});
	vector<point> ans;
	for(int i = 0; i < n; i++) {

		while(ans.size() >= 2 &&
			  dcmp(cross(ans.back() - ans[ans.size() - 2],
			             p[i] - ans.back())) <= 0)
		{
			ans.pop_back();
		}
		ans.push_back(p[i]);
	}

	return ans;
}

vector<point> minkowski_sum(vector<point> a, vector<point> b) { //闵可夫斯基和
	int n = a.size(), m = b.size();

	//把最低点放到第一个
	int ia = 0, ib = 0;

	for(int i = 1; i < n; i++) {
		if(a[i].y < a[ia].y ||
		  (dcmp(a[i].y - a[ia].y) == 0 && a[i].x < a[ia].x))
			ia = i;
	}

	for(int i = 1; i < m; i++) {
		if(b[i].y < b[ib].y ||
		  (dcmp(b[i].y - b[ib].y) == 0 && b[i].x < b[ib].x))
			ib = i;
	}

	rotate(a.begin(), a.begin() + ia, a.end());
	rotate(b.begin(), b.begin() + ib, b.end());

	//补上首点,方便处理边
	a.push_back(a[0]);
	b.push_back(b[0]);

	vector<point> ans;

	int i = 0, j = 0;

	ans.push_back(a[0] + b[0]);

	while(i < n || j < m) {
		Vector va, vb;

		if(i < n)
			va = a[i + 1] - a[i];

		if(j < m)
			vb = b[j + 1] - b[j];

		if(j == m || (i < n && dcmp(cross(va, vb)) > 0)) {
			ans.push_back(ans.back() + va);
			i++;
		}
		else if(i == n || dcmp(cross(va, vb)) < 0) {
			ans.push_back(ans.back() + vb);
			j++;
		}
		else {
			//两条边极角相同
			ans.push_back(ans.back() + va + vb);
			i++;
			j++;
		}
	}

	ans.pop_back();

	return ans;
}
posted @ 2023-04-16 10:57  Svemit  阅读(102)  评论(0)    收藏  举报