几个板子
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;
}

浙公网安备 33010602011771号