代码相关
upd on 26.3.4 代码风格由
const int maxn = 100005;
int a[maxn];
改为
const int maxn = 100000;
int a[maxn + 5];
以前代码有时间就该过来吧
字符串哈希
const int maxl = 100005;
const int mod1 = 1000000007;
const int base1 = 131;
const int mod2 = 998244353;
const int base2 = 233;
int powbase1[maxl] , powbase2[maxl];
void init(){
powbase1[0] = 1;
fo(i , 1 , maxl - 5)
powbase1[i] = 1ll * powbase1[i - 1] * base1 % mod1;
powbase2[0] = 1;
fo(i , 1 , maxl - 5)
powbase2[i] = 1ll * powbase2[i - 1] * base2 % mod2;
}
struct mystring{
string s;
int len;
pair<int , int> hsh[maxl];
void read(){
cin >> s;
len = s.size();
s = " " + s;
fo(i , 1 , len){
hsh[i].first = (1ll * hsh[i - 1].first * base1 % mod1 + s[i]) % mod1;
hsh[i].second = (1ll * hsh[i - 1].second * base2 % mod2 + s[i]) % mod2;
}
}
pair<int , int> gethash(int l , int r){
int ans1 = hsh[r].first;
int tmp1 = 1ll * hsh[l - 1].first * powbase1[r - l + 1] % mod1;
ans1 = (ans1 - tmp1 + mod1) % mod1;
int ans2 = hsh[r].second;
int tmp2 = 1ll * hsh[l - 1].second * powbase2[r - l + 1] % mod2;
ans2 = (ans2 - tmp2 + mod2) % mod2;
return mp(ans1 , ans2);
}
pair<int , int> gethash(){
return hsh[len];
}
};
树状数组
const int maxn = 100000;
struct Fenwick_Tree{
private:
int t[maxn + 5];
int lowbit(int x){
return x & -x;
}
public:
void updata(int x , int v){
for(int i = x ; i <= n ; i += lowbit(i))
t[i] += v;
}
int query(int x){
int ans = 0;
for(int i = x ; i ; i -= lowbit(i))
ans += t[i];
return ans;
}
int query(int l , int r){
return query(r) - query(l - 1);
}
};
线段树
从之前普通的版本改为动态开点
struct node{
friend node operator + (const node a , const node b){
}
};
struct Segment_Tree{
private:
int cnt , ls[maxn * 2 + 5] , rs[maxn * 2 + 5];
int lazy[maxn * 2 + 5];
node t[maxn * 2 + 5];
void modify(int v1 , int l , int r , int k){
}
void pushdown(int l , int r , int k){
int mid = (l + r) / 2;
if(ls[k] == 0) ls[k] = build(l , mid);
if(rs[k] == 0) rs[k] = build(mid + 1 , r);
modify(lazy[k] , l , mid , ls[k]);
modify(lazy[k] , mid + 1 , r , rs[k]);
lazy[k] = 0;
}
public:
int build(int l , int r){
int k = ++cnt;
// init t[k] and lazy[k]
return k;
}
void update(int L , int R , int v1 , int l , int r , int k){
if(L > R) return;
if(L <= l and r <= R){
modify(v1 , l , r , k);
return;
}
pushdown(l , r , k);
int mid = (l + r) / 2;
if(L <= mid) update(L , R , v1 , l , mid , ls[k]);
if(mid + 1 <= R) update(L , R , v1 , mid + 1 , r , rs[k]);
t[k] = t[ls[k]] + t[rs[k]];
}
node query(int L , int R , int l , int r , int k){
if(L <= l and r <= R) return t[k];
pushdown(l , r , k);
int mid = (l + r) / 2;
if(L <= mid){
node ans = query(L , R , l , mid , ls[k]);
if(mid + 1 <= R) return ans + query(L , R , mid + 1 , r , rs[k]);
else return ans;
}
else return query(L , R , mid + 1 , r , rs[k]);
}
}tr;
可持久化线段数
不想写喵,以后做题时写了再补上
线段树其他
动态开点、权值线段树的合并,支持单点修改,线段树二分以查询 lower_bound
struct Segment_Tree{
int cnt , ls[maxn * 20] , rs[maxn * 20];
struct node{
int sum , mx;
}t[maxn * 20];
node pushup(node a , node b){
node ans = {a.sum + b.sum , max(a.mx , b.mx)};
return ans;
}
int build(){
return ++cnt;
}
void updata(int x , int v , int l , int r , int k){
if(l == r){
t[k].sum += v;
if(t[k].sum) t[k].mx = l;
else t[k].mx = 0;
return;
}
int mid = (l + r) / 2;
if(x <= mid){
if(ls[k] == 0) ls[k] = ++cnt;
updata(x , v , l , mid , ls[k]);
}
else{
if(rs[k] == 0) rs[k] = ++cnt;
updata(x , v , mid + 1 , r , rs[k]);
}
t[k] = pushup(t[ls[k]] , t[rs[k]]);
}
int query(int x , int l , int r , int k){
// cerr << x << " " << l << " " << r << " " << k << "\n";
if(r < x) return t[k].mx;
if(l == r) return 0;
int mid = (l + r) / 2;
if(mid + 1 < x) return max(query(x , l , mid , ls[k]) , query(x , mid + 1 , r , rs[k]));
else return query(x , l , mid , ls[k]);
}
int merge(int l , int r , int k1 , int k2){
if(min(k1 , k2) == 0) return k1 + k2;
if(l == r){
t[k1].sum += t[k2].sum;
if(t[k1].sum) t[k1].mx = l;
else t[k1].mx = 0;
return k1;
}
int mid = (l + r) / 2;
ls[k1] = merge(l , mid , ls[k1] , ls[k2]);
rs[k1] = merge(mid + 1 , r , rs[k1] , rs[k2]);
t[k1] = pushup(t[ls[k1]] , t[rs[k1]]);
return k1;
}
}tr;
平衡树
#include<ctime>
#include<random>
#define mp make_pair
const int maxn = 100000;
mt19937 rd(time(0));
struct Treap{
private:
int rt , cnt , num[maxn + 5] , siz[maxn + 5] , pri[maxn + 5] , ls[maxn + 5] , rs[maxn + 5];
int build(int x){
cnt++;
num[cnt] = x , siz[cnt] = 1 , pri[cnt] = rd();
ls[cnt] = rs[cnt] = 0;
return cnt;
}
void pushup(int k){
siz[k] = siz[ls[k]] + siz[rs[k]] + 1;
}
int merge(int k1 , int k2){
if(min(k1 , k2) == 0) return max(k1 , k2);
if(pri[k1] > pri[k2]){
rs[k1] = merge(rs[k1] , k2);
pushup(k1);
return k1;
}
else{
ls[k2] = merge(k1 , ls[k2]);
pushup(k2);
return k2;
}
}
pair<int , int> split_val(int k , int key){
if(k == 0) return mp(0 , 0);
if(num[k] <= key){
pair<int , int> tmp = split_val(rs[k] , key);
rs[k] = tmp.first;
pushup(k);
return mp(k , tmp.second);
}
else{
pair<int , int> tmp = split_val(ls[k] , key);
ls[k] = tmp.second;
pushup(k);
return mp(tmp.first , k);
}
}
pair<int , int> split_siz(int k , int key){
if(k == 0) return mp(0 , 0);
if(siz[ls[k]] + 1 <= key){
pair<int , int> tmp = split_siz(rs[k] , key - siz[ls[k]] - 1);
rs[k] = tmp.first;
pushup(k);
return mp(k , tmp.second);
}
else{
pair<int , int> tmp = split_siz(ls[k] , key);
ls[k] = tmp.second;
pushup(k);
return mp(tmp.first , k);
}
}
public:
void init(){
rt = cnt = 0;
}
void insert(int x){
int k2 = build(x);
pair<int , int> tmp = split_val(rt , x);
int k1 = tmp.first , k3 = tmp.second;
rt = merge(k1 , merge(k2 , k3));
}
void del(int x){
pair<int , int> tmp = split_val(rt , x - 1);
int k1 = tmp.first , k23 = tmp.second;
tmp = split_siz(k23 , 1);
int k2 = tmp.first , k3 = tmp.second;
rt = merge(k1 , k3);
}
int rank(int x){
pair<int , int> tmp = split_val(rt , x - 1);
int k1 = tmp.first , k2 = tmp.second;
int ans = siz[k1] + 1;
rt = merge(k1 , k2);
return ans;
}
int query(int x){
pair<int , int> tmp = split_siz(rt , x - 1);
int k1 = tmp.first , k23 = tmp.second;
tmp = split_siz(k23 , 1);
int k2 = tmp.first , k3 = tmp.second;
int ans = num[k2];
rt = merge(k1 , merge(k2 , k3));
return ans;
}
int pre(int x){
pair<int , int> tmp = split_val(rt , x - 1);
int k12 = tmp.first , k3 = tmp.second;
tmp = split_siz(k12 , siz[k12] - 1);
int k1 = tmp.first , k2 = tmp.second;
int ans = num[k2];
rt = merge(k1 , merge(k2 , k3));
return ans;
}
int suf(int x){
pair<int , int> tmp = split_val(rt , x);
int k1 = tmp.first , k23 = tmp.second;
tmp = split_siz(k23 , 1);
int k2 = tmp.first , k3 = tmp.second;
int ans = num[k2];
rt = merge(k1 , merge(k2 , k3));
return ans;
}
};
ST 表
\([i - 2^j + 1 , i]\) 的 st 表,可实现在线插入
int lg[maxn + 5];
void init(){
lg[2] = 1;
fo(i , 3 , maxn + 1)
lg[i] = lg[i / 2] + 1;
}
struct Sparse_Table{
private:
int st[18][maxn + 5];
public:
void ins(int id , int num){
st[0][id] = num;
for(int j = 1 ; id - (1 << j) + 1 >= 1 ; j++){
st[j][id] = max(st[j - 1][id] , st[j - 1][id - (1 << j - 1)]);
}
}
int ask(int l , int r){
if(l > r) return -inf;
int k = lg[r - l + 1];
return max(st[k][r] , st[k][l + (1 << k) - 1]);
}
void clear(){
fo(j , 0 , 17)
fo(i , 1 , n)
st[j][i] = 0;
}
}
李超线段树
现在只写了支持全局线段插入,区间插入的以后再写
struct func{
long long a , b;
};
class lichao{
private:
func t[maxn << 2];
long long f(int x , func a){
return a.a * x + a.b;
}
public:
void build(int l , int r , int k){
t[k] = {0 , 0};
if(l == r) return;
int mid = (l + r) / 2;
build(l , mid , k << 1) , build(mid + 1 , r , k << 1 | 1);
}
void insert(func x , int l , int r , int k){
int mid = (l + r) / 2;
if(f(mid , t[k]) < f(mid , x)) swap(t[k] , x);
if(l == r) return;
if(x.a < t[k].a) insert(x , l , mid , k << 1);
else insert(x , mid + 1 , r , k << 1 | 1);
}
long long query(int x , int l , int r , int k){
if(l == r) return f(x , t[k]);
int mid = (l + r) / 2;
long long ans = f(x , t[k]);
if(x <= mid) return max(ans , query(x , l , mid , k << 1));
else return max(ans , query(x , mid + 1 , r , k << 1 | 1));
}
};
点分树
vector<int> e[maxn + 5];
int siz[maxn + 5];
bool vis[maxn + 5];
int get_root(int u , int sum , int fa){
int ans = -1;
siz[u] = 1;
bool flag = true;
for(int v : e[u]){
if(v == fa) continue;
if(vis[v]) continue;
int res = get_root(v , sum , u);
if(res != -1) ans = res;
if(siz[v] * 2 > sum) flag = false;
siz[u] += siz[v];
}
if(ans != -1) return ans;
if(flag and (sum - siz[u]) * 2 <= sum) return u;
return -1;
}
void solve(int rt , int sum){
vis[rt] = true;
for(int v : e[rt]){
if(vis[v]) continue;
int sumv = (siz[v] < siz[rt] ? siz[v] : sum - siz[rt]);
solve(get_root(v , sumv , 0) , sumv);
}
}
重链剖分
附加求 LCA 的代码
int siz[maxn + 5] , fa[maxn + 5] , dep[maxn + 5] , son[maxn + 5] , top[maxn + 5] , idx , dfn[maxn + 5];
void dfs1(int u , int f){
siz[u] = 1 , fa[u] = f , dep[u] = dep[f] + 1;
for(int v : e[u]){
if(v == f) continue;
dfs1(v , u);
siz[u] += siz[v];
if(siz[v] > siz[son[u]]) son[u] = v;
}
}
void dfs2(int u , int tp){
top[u] = tp;
dfn[u] = ++idx;
if(son[u]) dfs2(son[u] , tp);
for(int v : e[u]){
if(v == fa[u]) continue;
if(v == son[u]) continue;
dfs2(v , v);
}
}
void lca(int u , int v){
while(top[u] != top[v]){
if(dep[top[u]] < dep[top[v]]) swap(u , v);
u = fa[top[u]];
}
if(dep[u] < dep[v]) swap(u , v);
return v;
}
数论相关
现在只写了求逆元
int fac[maxn + 5] , inv[maxn + 5];
int qpow(int a , int b){
if(b == 0) return 1;
int ans = qpow(a , b / 2);
if(b % 2) return 1ll * ans * ans % mod * a % mod;
else return 1ll * ans * ans % mod;
}
// 记得一定要调用 init 喵,没调用全部草饲喵
void init(){
fac[0] = 1;
fo(i , 1 , maxn) fac[i] = 1ll * fac[i - 1] * i % mod;
inv[maxn] = qpow(fac[maxn] , mod - 2);
go(i , maxn - 1 , 0) inv[i] = 1ll * inv[i + 1] * (i + 1) % mod;
}
int getinv(int a){
return 1ll * inv[a] * fac[a - 1] % mod;
}
其他小trick
创建 \(n\) 行 \(m\) 列的矩阵
vector<vector<int>> dp(n + 5 , vector<int>(m + 5 , 0));
STL 的迭代器
set<node> :: iterator it = s.begin();
// 有一次将 set<node> :: iterator it 写成 set<int> :: iterator it 看了好久
// 当然你也可以放心用 auto
auto it = s.begin();
// 尽管 map set 不是线性的,但你仍然可以
it-- , it++;
// 来找它的前后继
priority_queue 的使用
priority_queue<node> q;
// 首先不要拼错,其次默认为大根堆
// 如果要小根堆
priority_queue<node , vector<node> , greater<node> > q;
// vector 表明实现方式, 即 node 是存在 vector 中的
// greater 与 less 相对, 表明从大到小
// 需要重载 > 号
在字符串后加字符
string s;
s = s + "I love Eleina"; // O(n)
s += "I love Eleina"; // O(1)
随机数
#include<ctime>
#include<random>
mt19937 rd(time(0));

浙公网安备 33010602011771号