杂
指针
在 lower_bound
, upper_bound
运用时的返回值是指针,可以用 auto
来存储(现在比赛基本都 c++14
了,放心用)。有时常见的解决方法为‘减去数组’,如:
int a[N], n, x;
int k = lower_bound(a + 1, a + n + 1, x) - a;
此外,还有很多 STL 函数的返回值是迭代器,与指针区别不大,可以视作指针。
但结构体数组或是一些 STL (如 set) 返回的好像不是很好操作,还是用 auto
存。以下为一些运用方法:
struct a{
int id;
bool f;
};
set<a> st;
//假设 set 中插入了很多值
auto k = upper_bound((a){1, 1});
a x = *k;
int y = k -> id; //等同于 y = x.id
bool z = k -> f; //等同于 z = x.f
if(k != st.end()){ //可以直接比较
k --; //将指针前移一位
}
重载运算符
常运用于结构体函数中,改变重载运算符号的作用。
一般形式为:
* operator *('const' * &x)'const'{}
第一个 *
为函数返回类型;第二个 *
为重载的运算符号;第三个 *
为读取的 \(x\) 的类型。
两个 const
都是可有可无的,但都有作用。第一个 const
可令 \(x\) 的值不会被改变;第二个 const
可令原有的进行运算的值不会被改变。
struct node{
int id;
bool f;
inline bool operator <(const node &x)const{
//返回类型为 bool, 重载 <,读入 x 类型为 node
//使 x 不会被更改,使 id、 f 不会被更改
//id, f 表示原结构体中的 id, f
//x.id, x.f 表示 x 中的 id, f
if(f ^ x.f) return f < x.f;
return id < x.id;
} //此结构体中的 < 以 f 为第一关键字,id 为第二关键字进行比较
};
set<node> st;
//此 set 中的 < 因 node 被重载而重载
曼哈顿距离和切比雪夫距离
曼哈顿距离
对于两个点 \((x_1, y_1), (x_2, y_2)\) ,他们的曼哈顿距离为 \(|x_1-x_2|+|y_1-y_2|\)
切比雪夫距离
对于两个点 \((x_1, y_1), (x_2, y_2)\) ,他们的切比雪夫距离为 \(max(|x_1-x_2|,|y_1-y_2|)\)
曼哈顿距离和切比雪夫距离的互化
将式子写成类似的形式:
- 曼哈顿距离:\(max(x_1-x_2+y_1-y_2,\ x_1-x_2-y_1+y_2,\ -x_1+x_2+y_1-y_2,\ -x_1+x_2,-y_1+y_2)\)
- 切比雪夫距离:\(max(x_1-x_2,\ -x_1+x_2,\ y_1-y_2,\ -y_1+y_2)\)
简单推导一下可以得出:
- 曼哈顿距离转切比雪夫距离:将每个点 \((x, y)\) 转化为 \((x+y, x-y)\)
- 切比雪夫距离转曼哈顿距离:将每个点 \((x, y)\) 转化为 \((\dfrac{x+y}{2}, \dfrac{x-y}{2})\)
极角排序
需要用到 atan2
函数
atan2(y,x)
返回浮点数,表示点 \((x, y)\) 与原点连线的 tan 值,值域为 \([-\pi,\pi]\)
用于极角排序时常是这样:
struct node{
int x, y;
};
inline bool cmp(node a, node b){ //此处排序为以默认原点为一端
double sum = atan2(a.y, a.x) - atan2(b.y, b.x);
if(!sum) return a.x < b.x;
return sum < 0;
}
范德蒙德卷积
用二项式定理可证
关于上下取整
- \(a\le\lfloor\frac{b}{c}\rfloor \rightarrow a\le\frac{b}{c}\)
- \(\frac{b}{c}\lt a \rightarrow\lfloor\frac{b}{c}\rfloor\lt a\)
- \(\lfloor\frac{a}{b}\rfloor+\lceil\frac{bx-a}{b}\rceil=x\)
区间 mex
在权值线段树上存 \(x\) 最后一次的出现位置
对于区间 \([l,r]\) ,在第 \(r\) 棵线段树上查找最小的值小于 \(l\) 的值即可
可以用可持久化在线优化到 log
Dfn序求 Lca
若点 \(x\) 的 Dfn序大于 \(y\) ,则将 \(x\) 一直往父亲跳直至 Dfn序小于等于 \(y\),再把 \(y\) 往上跳至同一位置即可
关于正确性,画图很好理解
图上查询两点是否在同一边双内
建出随意一颗生成树,对于所有的原边,在生成树上进行链覆盖
若两点间所有边覆盖次数都 \(\le 2\) ,则两点间必有两条及以上的不同路径,故在同一边双内