TOC

建议使用 Ctrl+F 搜索 .

目录

Updating...

语言:C++ .

因为时间错乱,所以 Code Style 混乱 .

未注明作者的都是自己写的 .

小工具 / C++ Tricks

NOI Linux 1.0

bashrc
  • title x:设置标题为 x
  • compile x:编译 x.cpp 并写入到可执行文件 x
  • compilerun xcompile x 并运行 x
function title() {
if [[ -z "$ORIG" ]]; then
ORIG=$PS1
fi
TITLE="\[\e]2;$*\a\]"
PS1=${ORIG}${TITLE}
} compile() {
g++ $1.cpp -lm -O2 -Wall -Wextra -std=c++14 -fsanitize=address,undefined -o $1
} compilerun() {
compile $1
./$1
}

Bash 命令:

  • source ~/.bashrc:快速应用 bashrc
  • alias x=y:设置 y 的别名为 x,等号没有空格 .
  • unalias x:取消 x 这个别名
vimrc

注意插入前先按 i!!

https://www.cnblogs.com/fushao2yyj/p/8404511.htmltabstop 改成 4 .

nanorc

注意反人类 nano 的快捷键

nano 快捷键
  • 保存:Ctrl + O 保存 .
  • 复制一整行:Alt + 6
  • 剪贴一整行:Ctrl + K
  • 复制/剪贴多行或者一行中的一部分:先将光标移动到需要复制/剪贴的文本的开头,按 Ctrl + 6Alt + A 做标记,然后移动光标到待复制/剪贴的文本末尾 . 这时选定的文本会反白,然后按复制一行的方法复制 . Ctrl + 6 取消 .
  • 粘贴:Ctrl + U
  • 搜索:Ctrl + W 然后输入搜索单词,Alt + W 跳转下一个
  • 退出:Ctrl + X,然后输入 Y 表示保存修改,N 不保存 . Ctrl + C 取消 .

Ref. https://zhuanlan.zhihu.com/p/259380222 .

set tabsize 4       # 设置制表符宽度
set autoindent # 允许自动缩进
set cut # 设置 CTRL-K 可以剪贴到行末
set noconvert # 不要转换 DOS/UNIX 换行符
set nowrap # 不要自动换行
set nohelp # 不显示下面两行帮助 (Alt+X 显示)
set morespace # 隐藏标题下的空白行,换取更多编辑空间
set smooth # 平滑卷屏
set suspend # 允许 ctrl-z 将 nano 置于后台
set smarthome # 第一次 Home 跳到行首非空字符,第二次到行首
set tabstospaces # 展开制表符为空格(如果需要的话)
set mouse # 允许鼠标
# set linenumbers # 显示行号(可以在编辑时 ALT-# 切换),NOI Linux 1.0 的 nano 太旧了不支持!
set backupdir path # 设置备份路径
set backup # 允许保存备份
set casesensitive # 搜索使用大小写敏感
set multibuffer # 使用 CTRL-r 读取文件时,默认读取到新缓存
set nonewlines # 不在文件末尾添加新行

快速读入 / 快速输出

快速读入 / 快速输出

简易小工具

will update .

Tools
namespace __TYPE__
{
typedef unsigned short u16;
typedef short i16;
typedef unsigned u32;
typedef int i32;
typedef unsigned long long u64;
typedef long long i64;
typedef unsigned long long u64;
typedef i64 ll;
typedef u64 ull;
};
template<typename T>
inline T chkmax(T& x, const T& y){if (x < y) x = y; return x;}
template<typename T>
inline T chkmin(T& x, const T& y){if (x > y) x = y; return x;}

无序映射器

pool (Mixed)

接口:

构建 pool : T -> unsigned 的映射 .

若 \(M\) 为 pool<T> 类型变量,满足若 \(x\neq y\),则 \(\operatorname{get}(x)\neq\operatorname{get}(y)\) .

template<typename T>
class pool
{
unordered_map<T, unsigned> pol;
unsigned cc;
public:
pool(){cc = 0;}
~pool() = default;
unsigned get(T x)
{
auto ptr = pol.find(x);
if (ptr == pol.end()){pol[x] = ++cc; return cc;}
else return ptr -> second;
}
unsigned size()const{return cc;}
void clear(){cc = 0; pol.clear();}
};

简易调试器

普通版

输出至 stderr,检测 ONLINE_JUDGE 宏来控制调试开关 .

#ifdef ONLINE_JUDGE
#define dputs
#define dout
#define dprintf
#else // debug 至 stderr .
#define dputs(x) fputs(x"\n", stderr)
#define dprintf(F...) fprintf(stderr, F)
#define dout cerr
#endif
来自 C++ Tricks
#define error(args...) { string _s = #args; replace(_s.begin(), _s.end(), ',', ' '); stringstream _ss(_s); istream_iterator<string> _it(_ss); err(_it, args); }

void err(istream_iterator<string> it) {}
template<typename T, typename... Args>
void err(istream_iterator<string> it, T a, Args... args) {
cerr << *it << " = " << a << endl;
err(++it, args...);
}

文件 IO

文件 IO
#define ifile(x) freopen(x".in", "r", stdin)
#define ofile(x) freopen(x".out", "w", stdout)
#define file(x) {ifile(x); ofile(x);}
#define ifile(x) freopen(#x".in", "r", stdin)
#define ofile(x) freopen(#x".out", "w", stdout)
#define file(x) {ifile(x); ofile(x);}

位运算

BITWISE
namespace BITWISE
{
using __TYPE__ :: i64;
inline int ctz(int x){return __builtin_ctz(x);}
inline int clz(int x){return __builtin_clz(x);}
inline int ffs(int x){return __builtin_ffs(x);}
inline int popcnt(int x){return __builtin_popcount(x);}
inline int lowbit(int x){return x & -x;}
inline i64 ctzl(i64 x){return __builtin_ctzll(x);}
inline i64 clzl(i64 x){return __builtin_clzll(x);}
inline i64 ffsl(i64 x){return __builtin_ffsll(x);}
inline i64 popcntl(i64 x){return __builtin_popcountll(x);}
inline i64 lowbitl(i64 x){return x & -x;}
}

Smart Double

Smart Double

数论

GCD

数论只会 GCD

辗转相除法
inline int gcd(int a, int b){return b ? gcd(b, a%b) : a;}
Stein 算法

基于值域预处理的快速 GCD
// i don't know that.

快速幂相关

log 快速幂
inline int qpow(int a, int n)
{
int ans = 1;
while (n)
{
if (n & 1) ans = 1ll * ans * a % P;
a = 1ll * a * a % P; n >>= 1;
} return ans;
}
线性筛(指数不变 O(1) 求幂)
inline void linear_sieve(int n)
{
notprime[1] = true; power[1] = 1;
for (int i=2;i<=n;i++)
{
if (!notprime[i]){plist.emplace_back(i); power[i] = qpow(i, k);}
for (auto x : plist)
{
int now = i*x;
if (now > n) break;
notprime[now] = true;
if (!(i%x)){power[now] = 1ll * power[i] * power[x] % P; break;}
power[now] = 1ll * power[i] * power[x] % P;
}
}
}
光速幂(底数不变 O(1) 求幂)
// 值域 2^31-1
template<int MOD>
struct FastPow
{
private:
ll p1[66666], p2[66666];
static ll qpow(ll a,ll n){/**/}
public:
explicit FastPow(ll a)
{
ll t1=a,t2=qpow(t1,65536); p1[0]=p2[0]=1;
for (int i=1; i<65536; i++) p1[i] = p1[i-1] * t1 % MOD;
for (int i=1; i<65536; i++) p2[i] = p2[i-1] * t2 % MOD;
}
ll operator()(unsigned n){return p2[n>>16] % MOD * p1[n&65535] % MOD;}
};

分数模板类

EI 的取模还原分数

取模还原分数 (by Elegia)

https://blog.csdn.net/EI_Captain/article/details/117172239

pair<int, int> approx(int p, int q, int A) {
int x = q, y = p, a = 1, b = 0;
while (x > A) {
swap(x, y); swap(a, b);
a -= x / y * b;
x %= y;
}
return make_pair(x, a);
}

逆元

模素数单个逆元

任意模数单个逆元 (exgcd)
ll inv(ll a, ll P){ll x ,y, d = exgcd(a ,P, x, y); return (d == 1) ? x % P : -1;}
线性求一行逆元

整除分块

一维整除分块

二维整除分块

线性筛

线性筛素数、欧拉函数、莫比乌斯函数
inline void linear_sieve(int n)
{
notprime[1] = true; phi[1] = mu[1] = 1;
for (int i=2; i<=n; i++)
{
if (!notprime[i]){plist.emplace_back(i); phi[i] = i-1; mu[i] = -1;}
for (auto x : plist)
{
int now = i*x;
if (now > n) break;
notprime[now] = true;
if (!(i%x)){phi[now] = phi[i] * x; mu[now] = 0; break;}
phi[now] = phi[i] * phi[x]; mu[now] = mu[i] * mu[x];
}
}
}

扩展欧几里得算法 (exgcd)

传引用的 exgcd
ll exgcd(ll a,ll b,ll& x,ll& y)
{
if (!b){x = 1; y = 0; return a;}
ll _ = exgcd(b, a%b, x, y), old_x = x, old_y = y;
x = old_y; y = old_x - (a/b) * old_y;
return _;
}
返回 pair 的 exgcd

类欧几里得算法

中国剩余定理 (CRT) & exCRT

BSGS & exBSGS

积性函数筛子

组合计数

组合数取模

杨辉三角
预处理阶乘及其逆元
Lucas
exLucas
using namespace std;
typedef long long ll;
ll qpow(ll a,ll n,ll p){/**/}
namespace extra_lucas_detail
{
ll fac(ll n,ll p,ll pk)
{
if (!n) return 1;
ll ans=1;
for (int i=1;i<pk;i++)
if (i%p) ans=ans*i%pk;
ans=qpow(ans,n/pk,pk);
for (int i=1; i<=n%pk;i++)
if (i%p) ans=ans*i%pk;
return ans*fac(n/p,p,pk)%pk;
}
ll exgcd(ll a,ll b,ll& x,ll& y){/**/}
ll inv(ll a,ll P){ll x,y,d=exgcd(a,P,x,y); return (d==1)?x%P:-1;}
ll C(ll n,ll m,ll p,ll pk)
{
if (n<m) return 0;
ll A=fac(n,p,pk),B=fac(m,p,pk),C=fac(n-m,p,pk),cnt=0;
for (ll i=n;i;i/=p) cnt+=i/p;
for (ll i=m;i;i/=p) cnt-=i/p;
for (ll i=n-m;i;i/=p) cnt-=i/p;
return A*inv(B,pk)%pk*inv(C,pk)%pk*qpow(p,cnt,pk)%pk;
}
}
ll exlucas(ll n,ll m,ll p)
{
using namespace extra_lucas_detail;
ll ans=0,P=p;
for (int i=2;(p>1)&&(i*i<=p);i++)
{
ll pk=1;
while (!(p%i)){p/=i; pk*=i;}
if (pk>1)
{
ll now=C(n,m,i,pk);
ans=(ans+now*(P/pk)%P*inv(P/pk,pk)%P)%P;
}
}
if (p>1)
{
ll now=C(n,m,p,p);
ans=(ans+now*(P/p)%P*inv(P/p,p)%P)%P;
} return (ans%P+P)%P;
}

伯努利数

斯特林数

Catalan 数

Cantor 展开

LGV 引理

矩阵树定理

线性代数

矩阵类

图论

Simple Graph

Simple Graph
template<typename T>
struct Graph
{
typedef vector<pair<int, T> > _;
_ g[N];
inline void addedge(int u, int v, ll w){g[u].emplace_back(make_pair(v, w));}
inline void ade(int u, int v, ll w){addedge(u, v, w); addedge(v, u, w);}
inline _ edges(const unsigned& id)const{return g[id];}
inline _& edges(const unsigned& id){return g[id];}
inline _ operator [] (const unsigned& id)const{return edges(id);}
inline _& operator [] (const unsigned& id){return edges(id);}
inline void clear(){for (int i=0; i<N; i++) g[i].clear();}
};

单源最短路径 (SSSP)

无负权:

Dijkstra 堆优化
struct Node
{
int idx, d;
Node(int _=0, int __=0){idx = _; d = __;}
inline bool operator <(const Node& a)const{return d>a.d;}
};
void dijkstra(int s)
{
memset(dis, 0x3f, sizeof dis);
memset(vis, false, sizeof vis);
priority_queue<Node> q; dis[s]=0; q.push(Node(s, dis[s]));
while (!q.empty())
{
auto now = q.top(); q.pop();
int u = now.idx;
if (vis[u]) continue;
vis[u] = true;
for (auto _ : g[u])
{
int v = _.first, w = _.second;
if (vis[v]) continue;
if (dis[v] > dis[u]+w){dis[v] = dis[u]+w; q.push(Node(v, dis[v]));}
}
}
}

有负权 / 判负环:

Bellman-Ford

Bellman-Ford:

// a 存边
bool bellman_ford(int s)
{
memset(dis, 0x3f, sizeof dis);
dis[s] = 0; int t = 0;
for (int i=1; i<n; i++)
for (int j=0; j<m; j++)
{
int u = a[j].u, v = a[j].v, w = a[j].w;
if (dis[v] > dis[u] + w) dis[v] = dis[u] + w;
}
for (int i=0; i<m; i++)
{
int u = a[j].u, v = a[j].v, w = a[j].w;
if (dis[v] > dis[u] + w) return false;
} return true;
}

SPFA:

// 入队次数超过 n 则有负环
inline void spfa(int x)
{
memset(dis, 0x3f, sizeof dis); memset(vis, 0, sizeof vis);
queue<int> q; vis[x] = true; dis[x] = 0; q.push(x);
while (!q.empty())
{
int u = q.front(); q.pop();
for (auto e : g[u])
{
int v = e.first, w = e.second;
if (dis[v] > dis[u] + w){dis[v] = dis[u] + w; if (!vis[v]) q.push(v), vis[v] = true;}
} vis[now] = false;
}
}
EI Magic (by Elegia)

https://www.cnblogs.com/Elegia/p/16122335.html

Bonus: 差分约束 .

多源最短路径

Floyd 全源最短路

Johnson 全源最短路

最短路图

最短路图

假装求最短路的函数是 SSSP(Graph, distance, u) .


k 短路

A*

持久化可并堆

同余最短路

跳楼机

给定 \(x,y,z,h\),问有多少个 \(k\in[1,h]\) 使得 \(k=px+qy+rz\),其中 \(p,q,r\) 是变量 .

using namespace std;
const int N=1e5+500;
typedef unsigned long long ull;
typedef long long ll;
ll x,y,z,h,dis[N];
bool vis[N];
typedef vector<pair<ll,ll> > graph[N];
graph g;
inline void addedge(ll u,ll v,ll w){g[u].push_back(make_pair(v,w));}
struct node
{
int idx; ll dis;
node(int _=0,ll __=0){idx=_; dis=__;}
bool operator <(const node& u)const{return dis>u.dis;}
};
void dijkstra(int s){/**/}
int main()
{
scanf("%lld%lld%lld%lld",&h,&x,&y,&z);
if ((x==1)||(y==1)||(z==1)){printf("%lld",h); return 0;}
if (x>y) swap(x,y);
if (y>z) swap(y,z);
if (x>z) swap(x,z);
if (x>y) swap(x,y);
if (y>z) swap(y,z);
if (x>z) swap(x,z);
for (int i=0;i<x;i++) addedge(i,(i+y)%x,y),addedge(i,(i+z)%x,z);
dijkstra(0); ll ans=0;
for (int i=0;i<x;i++)
if (h>=dis[i]) ans+=(h-dis[i]-1)/x+1;
printf("%lld",ans);
return 0;
}

欧拉图 / 欧拉路

欧拉图判定

找一条欧拉路

一般图支配树

一般图支配树

https://www.luogu.com.cn/record/54432641

using namespace std;
typedef long long ll;
const int N=205000,M=20*N;
int n,m;
int head[N],shead[N],ihead[N],rhead[N],ver[M],nxt[M],tot=-1;
int siz[N],father[N],fa[N];
int dfn[N],id[N],low[N],sdom[N],idom[N],cnt;
void addedge(int head[],int u,int v){ver[++tot]=v; nxt[tot]=head[u]; head[u]=tot;}
void init(int n){for (int i=1;i<=n;i++) sdom[i]=low[i]=fa[i]=i;}
void dfs1(int u)
{
dfn[u]=++cnt; id[cnt]=u;
for (int i=head[u];~i;i=nxt[i])
{
int v=ver[i];
if (dfn[v]) continue;
father[v]=u; dfs1(v);
}
}
int get(int u)
{
if (u==fa[u])return u;
int root=get(fa[u]);
if (dfn[sdom[low[fa[u]]]]<dfn[sdom[low[u]]]) low[u]=low[fa[u]];
return fa[u]=root;
}
void tarjan()
{
int v;
for (int i=cnt;i>1;i--)
{
int u=id[i];
for (int j=rhead[u];~j;j=nxt[j])
{
v=ver[j];
if (!dfn[v]) continue;
get(v);
if (dfn[sdom[low[v]]]<dfn[sdom[u]]) sdom[u]=sdom[low[v]];
}
addedge(shead,sdom[u],u);
fa[u]=father[u];
u=father[u];
for (int j=shead[u];~j;j=nxt[j])
{
v=ver[j]; get(v);
if (sdom[low[v]]==u) idom[v]=u;
else idom[v]=low[v];
}
shead[u]=-1;
}
for (int i=2;i<=cnt;i++)
{
int u=id[i];
if (idom[u]!=sdom[u]) idom[u]=idom[idom[u]];
}
}
void dfs2(int u)
{
siz[u]=1;
for(int i=ihead[u];~i;i=nxt[i])
{
int v=ver[i];
dfs2(v);
siz[u]+=siz[v];
}
}
int main()
{
memset(head,-1,sizeof head);
memset(ihead,-1,sizeof ihead);
memset(rhead,-1,sizeof rhead);
memset(shead,-1,sizeof shead);
scanf("%d%d",&n,&m);
for (int i=1,u,v;i<=m;i++){scanf("%d%d",&u,&v); addedge(head,u,v); addedge(rhead,v,u);}
init(n);
dfs1(1);
tarjan();
for (int i=2;i<=n;i++)
if (idom[i]) addedge(ihead,idom[i],i);
dfs2(1);
for (int i=1;i<=n;i++) printf("%d ",siz[i]);
return 0;
}

最小生成树 (MST)

Kruskal

Prim

Boruvka

连通性 (Tarjan)

2-SAT

Floyd

全源最短路

全源最短路 - Floyd .

传递闭包
bool dp[N][N];
void Floyd()
{
for (int k=1; k<=n; k++)
for (int i=1; i<=n; i++)
for (int j=1; j<=n; j++)
dp[i][j] = dp[i][j] | (dp[i][k] & dp[k][j]);
}
最小环

二分图

图的匹配

Prufer 序列

网络流

DAG 上问题

拓扑排序

支配树

https://www.luogu.com.cn/record/54416499

int lca(int p1,int p2)
{
if (dep[p1]<dep[p2]) swap(p1,p2);
for (int i=18;i>=0;i--)
if (dep[f[p1][i]]>=dep[p2]) p1=f[p1][i];
if (p1==p2) return p2;
for (int i=18;i>=0;i--)
if (f[p1][i]!=f[p2][i]) p1=f[p1][i],p2=f[p2][i];
return f[p1][0];
}
void topsort()
{
queue<int> q;
for (int i=1;i<=n;i++)
if (!deg[i]) q.push(i),father[i]=0;
while (!q.empty())
{
int u=q.front(),fa=father[u]; q.pop();
addedge(shead,fa,u);
f[u][0]=fa; dep[u]=dep[fa]+1;
for (int i=1;i<=22;i++) f[u][i]=f[f[u][i-1]][i-1];
for (int i=head[u];~i;i=nxt[i])
{
int v=ver[i]; --deg[v];
if (!deg[v]) q.push(v);
if (father[v]==-1) father[v]=u;
else father[v]=lca(father[v],u);
}
}
}

树上问题 - 最近公共祖先 (LCA)

倍增 LCA
int n,m,s,dep[N],f[N][LgN+10];
bool vis[N];
inline void dfs(int now,int fa)
{
f[now][0]=fa; dep[now]=dep[fa]+1; int s=g[now].size();
for (int i=1;i<=LgN;i++) f[now][i]=f[f[now][i-1]][i-1];
for (int i=0;i<s;i++)
if (g[now][i]!=fa) dfs(g[now][i],now);
}
inline int lca(int p1,int p2)
{
if (dep[p1]<dep[p2]) swap(p1,p2);
for (int i=18;i>=0;i--)
if (dep[f[p1][i]]>=dep[p2]) p1=f[p1][i];
if (p1==p2) return p2;
for (int i=18;i>=0;i--)
if (f[p1][i]!=f[p2][i]) p1=f[p1][i],p2=f[p2][i];
return f[p1][0];
}
Tarjan 算法离线 LCA

树剖求 LCA
namespace LCA
{
int fa[N], dep[N], siz[N], son[N], top[N], dfn[N], rnk[N], cc;
void dfs1(int u)
{
siz[u] = 1;
for (auto v : g[u])
{
if (fa[u] == v) continue;
dep[v] = dep[u] + 1;
fa[v] = u;
dfs1(v);
siz[u] += siz[v];
if (!son[u]|| (siz[v] > siz[son[u]])) son[u] = v;
}
}
void dfs2(int u, int t)
{
top[u] = t;
rnk[++cc] = u; dfn[u] = cc;
if (!son[u]) return ;
dfs2(son[u], t);
for (auto v : g[u])
if ((v != son[u]) && (v != fa[u])) dfs2(v, v);
}
int lca(int u, int v)
{
while (top[u] != top[v])
{
if (dep[top[u]] > dep[top[v]]) u = fa[top[u]];
else v = fa[top[v]];
}
return dep[u] > dep[v] ? v : u;
}
}

树上问题

树的直径与重心

树链剖分 (HLD)

LOJ #139

树上问题 - 树同构判定

字符串

字符串 Hash

BKDR Hash

Trie 相关

普通 Trie

01 Trie

压缩 Trie

Manacher

Manacher

KMP

KMP
typedef char str[N];
typedef long long ll;
str s1, s2;
int l1, l2, nxt[N], f[N];
void getnxt()
{
nxt[1] = 0; int j = 0;
for (int i=2; i<=l2; i++)
{
while (j && (s2[i] != s2[j+1])) j = nxt[j];
if (s2[i] == s2[j+1]) ++j;
nxt[i] = j;
}
}
void kmp()
{
int j = 0;
for (int i=1; i<=l1; i++)
{
while ((j==l2) || (j && (s1[i] != s2[j+1]))) j = nxt[j];
if (s1[i] == s2[j+1]) ++j;
f[i] = j;
}
}

Border Theory

Border 树
// 上接 KMP
getnxt();
for (int i=1; i<=l; i++) G.ade(i, nxt[i]);

Z Algorithm

Z Algorithm

AC 自动机

AC Automaton
// Sig 字符集(
// 此处字符集为小写字母('a' ~ 'z')
const int N = 1e6 + 50, Sig = 26;
struct AC
{
int tr[N][Sig], fail[N], mark[N], cc, root;
inline void insert(string s)
{
int u = root, l = s.length();
for (int i=0; i<l; i++)
{
if (!tr[u][s[i] - 'a']) tr[u][s[i] - 'a'] = ++cc;
u = tr[u][s[i] - 'a'];
} ++mark[u];
}
inline void build()
{
queue<int> q; fail[root] = root;
for (int i=0; i<Sig; i++)
{
if (tr[root][i]){q.push(tr[root][i]); fail[tr[root][i]] = root;}
else tr[root][i] = root;
}
while (!q.empty())
{
int u = q.front(); q.pop();
for (int i=0; i<Sig; i++)
{
if (tr[u][i]){fail[tr[u][i]] = tr[fail[u]][i]; q.push(tr[u][i]);} // trie
else tr[u][i] = tr[fail[u]][i]; // automaton
}
}
}
inline int query(string s)
{
int u = root, ans = 0, l = s.length();
for (int i=0; i<l; i++)
{
u = tr[u][s[i] - 'a'];
for (int j = u; j && ~mark[j]; j = fail[j]){ans += mark[j]; mark[j] = -1;}
} return ans;
}
inline void clear(){memset(tr, 0, sizeof tr); memset(mark, 0, sizeof mark); cc = 0;}
AC(){root = cc = 0;}
}ac;
AC Automaton + fail 树
const int N = 1e6 + 50, Sig = 26;
int n;inline int trans(const char& c){return c - 'a';}
struct SimpleGraph
{
vector<int> g[N];
inline void addedge(int u,int v){g[u].emplace_back(v);}
inline void ade(int u,int v){addedge(u, v); addedge(v, u);}
vector<int>& operator [](const int& idx){return g[idx];}
inline vector<int>& out_edges(int u){return g[u];}
};
struct AC
{
SimpleGraph FT; // fail tree
int tr[N][Sig], fail[N], ed[N], siz[N], cc, root;
inline void insert(int id, string s)
{
int u = root, l = s.length();
for (int i=0; i<l; i++)
{
int _ = trans(s[i]);
if (!tr[u][_]) tr[u][_] = ++cc;
u = tr[u][_]; ++siz[u];
} ed[id] = u;
}
inline void build()
{
queue<int> q;
for (int i=0; i<Sig; i++)
{
if (tr[root][i]){q.push(tr[root][i]); fail[tr[root][i]] = root;}
else tr[root][i] = root;
}
while (!q.empty())
{
int u = q.front(); q.pop();
for (int i=0; i<Sig; i++)
{
if (tr[u][i]){q.push(tr[u][i]); fail[tr[u][i]] = tr[fail[u]][i];}
else tr[u][i] = tr[fail[u]][i];
} FT.addedge(fail[u], u);
}
}
void dfs(int u){for (int v : FT[u]) dfs(v), siz[u] += siz[v];}
inline void query(string s){dfs(0);}
AC(){cc = root = 0;}
}ac;

后缀数组 (SA)

后缀树 (ST)

后缀平衡树

后缀自动机 (SAM)

回文自动机 (PAM)

最小表示法

数据结构

链表

链表
// 我不会链表

单调数据结构

单调栈

单调队列

ST 表

ST 表
// 传入一个 Functor 给 op,要求:
// 1. op(x, x) = x (可重复贡献)
// 2. op(x, op(y, z)) = op(op(x, y), z) (结合律)
template<typename T, typename op>
struct ST
{
typedef unsigned U;
T f[N][LgN+10];
template<typename rit>
inline void reset(rit fst, rit sec)
{
const U n = sec - fst;
for (U i=1; i<=n; i++) f[i][0] = *(fst + (i-1));
for (U j=1; (1u<<j)<=n; j++)
for (U i=1; i+(1u<<j)-1u<=n; i++) f[i][j] = op()(f[i][j-1], f[i + (1<<(j-1))][j-1]);
}
inline T query(U l, U r)const{U _ = log2(r-l+1); return op()(f[l][_], f[r-(1<<_)+1][_]);}
template<typename rit>
ST(rit fst, rit sec){init(fst, sec);}
ST() = default;
~ST() = default;
};
ST 表,但是查询最值位置
// 传入一个 Functor 给 op,要求:
// 1. op(x, x) = x (可重复贡献)
// 2. op(x, op(y, z)) = op(op(x, y), z) (结合律)
template<typename T, typename op>
struct ST
{
typedef unsigned U;
T f[N][LgN+10]; U pos[N][LgN+10];
template<typename rit>
inline void reset(rit fst, rit sec)
{
const U n = sec - fst;
for (U i=1; i<=n; i++){f[i][0] = *(fst + (i-1)); pos[i][0] = i;}
for (U j=1; (1u<<j)<=n; j++)
for (U i=1; i+(1u<<j)-1u<=n; i++)
{
if (op()(f[i][j-1], f[i+(1<<(j-1))][j-1])){f[i][j] = f[i][j-1]; pos[i][j] = pos[i][j-1];}
else{f[i][j] = f[i+(1<<(j-1))][j-1]; pos[i][j] = pos[i+(1<<(j-1))][j-1];}
}
}
inline T query(U l, U r)const{U _ = log2(r-l+1); return op()(f[l][_], f[r-(1<<_)+1][_]);}
inline U querypos(U l, U r)const{U _ = log2(r-l+1);return op()(f[l][_], f[r-(1<<_)+1][_]) ? pos[l][_] : pos[r-(1<<_)+1][_];}
template<typename rit>
ST(rit fst, rit sec){init(fst, sec);}
ST() = default;
~ST() = default;
};

树状数组

树状数组 - 单点加区间查

树状数组 - 区间加单点查

树状数组 - 区间加区间查

线段树

普通线段树 (Segment Tree)

区间赋值,区间 min .

struct SMT
{
#define ls u << 1
#define rs u << 1 | 1
struct Node{int l, r, m, lazy;}tr[4*N];
inline void pushup(int u){tr[u].m = min(tr[ls].m, tr[rs].m);}
inline void pushdown(int u)
{
if (!tr[u].lazy) return ;
tr[ls].m = tr[rs].m = tr[u].lazy;
tr[ls].lazy = tr[rs].lazy = tr[u].lazy;
tr[u].lazy = 0;
}
void build(int u, int l, int r)
{
tr[u].l = l; tr[u].r = r;
if (l == r){tr[u].m = w[rnk[l]]; return ;}
int mid = (l + r) >> 1;
build(ls, l, mid); build(rs, mid+1, r);
pushup(u);
}
void change(int u, const int& l, const int& r, const int& x)
{
int L = tr[u].l, R = tr[u].r;
if ((l <= L) && (R <= r)){tr[u].m = tr[u].lazy = x; return ;}
pushdown(u);
int mid = (L + R) >> 1;
if (l <= mid) change(ls, l, r, x);
if (r > mid) change(rs, l, r, x);
pushup(u);
}
int query(int u, const int& l, const int& r)
{
int L = tr[u].l, R = tr[u].r;
if ((l <= L) && (R <= r)) return tr[u].m;
pushdown(u);
int ans = INF, mid = (L + R) >> 1;
if (l <= mid) chkmin(ans, query(ls, l, r));
if (r > mid) chkmin(ans, query(rs, l, r));
return ans;
}
#undef rs
#undef ls
}T;
线段树合并

雨天的尾巴

using namespace std;
const int N = 1e5+50;
typedef long long ll;
typedef pair<int, int> pii;
template<typename T>
inline int chkmin(T& a, const T& b){if (a > b) a = b; return a;}
template<typename T>
inline int chkmax(T& a, const T& b){if (a < b) a = b; return a;}
int n, m, root[N], ans[N];
vector<int> g[N], G;
inline void addedge(int u, int v){g[u].emplace_back(v);}
inline void ade(int u, int v){addedge(u, v); addedge(v, u);}
struct Query{int x, y, z;}q[N];
namespace LCA{/*树剖 LCA*/}
struct Node //
{
int p, cnt;
Node(int _, int __) : p(_), cnt(__){}
Node() = default;
bool operator < (const Node& rhs)const{return (cnt == rhs.cnt) ? p > rhs.p : cnt < rhs.cnt;}
Node operator + (const Node& rhs)const{return Node(max(p, rhs.p), cnt+rhs.cnt);}
Node& operator += (const Node& rhs){return *this = *this + rhs;}
};
struct SMF
{
int ch[40*N][2], cc;
Node v[40*N];
inline void pushup(int u){v[u] = max(v[ch[u][0]], v[ch[u][1]]);}
inline void insert(int& u, int l, int r, Node _)
{
if (!u) u = ++cc;
if (l == r){v[u] += _; return ;}
int mid = (l + r) >> 1, p = _.p;
if (p <= mid) insert(ch[u][0], l, mid, _);
else insert(ch[u][1], mid+1, r, _);
pushup(u);
}
inline void merge(int& x, int y, int l, int r) // this m
{
if (!x || !y){x += y; return ;}
if (l == r){v[x] += v[y]; return ;}
int mid = (l + r) >> 1;
merge(ch[x][0], ch[y][0], l, mid);
merge(ch[x][1], ch[y][1], mid+1, r);
pushup(x);
}
}T;
vector<Node> mdf[N];
int R;
void dfs(int u)
{
for (int v : g[u])
if (v != LCA::fa[u]){dfs(v); T.merge(root[u], root[v], 1, R);}
for (auto e : mdf[u]) T.insert(u, 1, R, e);
if (T.v[u].p) ans[u] = G[T.v[u].p - 1];
}
inline int discrete(int w){return lower_bound(G.begin(), G.end(), w) - G.begin()+1;}
int main()
{
using namespace LCA;
scanf("%d%d", &n, &m);
for (int i=1, u, v; i<n; i++){scanf("%d%d", &u, &v); ade(u, v);}
dep[1] = 1; dfs1(1); dfs2(1, 1);
for (int i=1; i<=m; i++) scanf("%d%d%d", &q[i].x, &q[i].y, &q[i].z), ++q[i].z, G.emplace_back(q[i].z);
stable_sort(G.begin(), G.end());
G.erase(unique(G.begin(), G.end()), G.end());
R = G.size()+1;
for (int i=1; i<=m; i++)
{
int x = q[i].x, y = q[i].y, z = discrete(q[i].z), _ = lca(x, y);
mdf[x].emplace_back(Node(z, 1)); mdf[y].emplace_back(Node(z, 1));
mdf[_].emplace_back(Node(z, -1)); mdf[fa[_]].emplace_back(Node(z, -1));
}
for (int i=1; i<=n; i++) T.insert(root[i], i, i, Node());
dfs(1);
for (int i=1; i<=n; i++) printf("%d\n", max(0, ans[i]-1));
return 0;
}
线段树分裂
李超线段树 (Li-chao Tree)

HEOI2013 Segment

using namespace std;
const int N=2e5+500;
typedef pair<double,int> pdi;
struct line{double k,b;}p[N];
int s[N],cnt,n;
double calc(int id,int d){return p[id].b+p[id].k*d;}
void add(int x0,int y0,int x1,int y1)
{
++cnt;
if (x0==x1){p[cnt].k=0; p[cnt].b=max(y0,y1);}
else{p[cnt].k=1.0*(y1-y0)/(x1-x0); p[cnt].b=y0-p[cnt].k*x0;}
}
void update(int root,int cl,int cr,int l,int r,int u)
{
int v=s[root],mid=(cl+cr)>>1;
bool UgV=calc(u,mid)>calc(v,mid);
if ((r<cl)||(cr<l)) return ;
if ((l<=cl)&&(cr<=r))
{
if (cl==cr) // leaf
{
if (UgV) s[root]=u;
return ;
}
if (p[v].k<p[u].k)
{
if (UgV){s[root]=u; update(root<<1,cl,mid,l,r,v);}
else update(root<<1|1,mid+1,cr,l,r,u);
}
else if (p[v].k>p[u].k)
{
if (UgV){s[root]=u; update(root<<1|1,mid+1,cr,l,r,v);}
else update(root<<1,cl,mid,l,r,u);
}
else{if (p[u].b>p[v].b) s[root]=u;}
return ;
}
update(root<<1,cl,mid,l,r,u);
update(root<<1|1,mid+1,cr,l,r,u);
}
pdi Max(const pdi& A,const pdi& B)
{
if (A.first==B.first) return A.second>B.second?B:A;
else return A.first>B.first?A:B;
}
pdi query(int root,int l,int r,int d)
{
if ((r<d)||(d<l)) return make_pair(0.0,0);
int mid=(l+r)>>1; pdi ans=make_pair(calc(s[root],d),s[root]);
if (l==r) return ans;
return Max(ans,Max(query(root<<1,l,mid,d),query(root<<1|1,mid+1,r,d)));
}
int main()
{
scanf("%d",&n); int opt,x0,y0,x1,y1,k,lastans=0;
while (n--)
{
scanf("%d",&opt);
if (!opt)
{
scanf("%d",&k); k=(k+lastans-1+39989)%39989+1; // no UB
printf("%d\n",lastans=query(1,1,39989,k).second);
}
else
{
scanf("%d%d%d%d",&x0,&y0,&x1,&y1);
x0=(x0+lastans-1+39989)%39989+1; x1=(x1+lastans-1+39989)%39989+1;
y0=(y0+lastans-1+1000000000)%1000000000+1;
y1=(y1+lastans-1+1000000000)%1000000000+1;
if (x0>x1) swap(x0,x1),swap(y0,y1);
add(x0,y0,x1,y1);
update(1,1,39989,x0,x1,cnt);
}
} return 0;
}
吉司机线段树 (Segment Tree beats!)

兔队线段树 (楼房重建)

从《楼房重建》出发浅谈一类使用线段树维护前缀最大值的算法

using namespace std;
const int N=1e5+500,M=1<<18|7;
typedef long long ll;
int n,q,id[M],cnt[M];
ll h[N];
bool gt(int p1,int p2)
{
if (!p2) return h[p1];
return h[p1]*p2>h[p2]*p1;
}
void build(int u,int l,int r)
{
id[u]=l; cnt[u]=1;
if (l==r) return ;
int mid=(l+r)>>1;
build(u<<1,l,mid); build(u<<1|1,mid+1,r);
}
int calc(int u,int l,int r,int p)
{
if (l==r) return gt(l, p);
int mid=(l+r)>>1;
if (gt(id[u<<1],p)) return calc(u<<1,l,mid,p)+cnt[u];
else return calc(u<<1|1,mid+1,r,p);
}
void modify(int u,int l,int r,int p)
{
if (l==r) return ;
int mid=(l+r)>>1;
if (p<=mid) modify(u<<1,l,mid,p);
else modify(u<<1|1,mid+1,r,p);
id[u]=gt(id[u<<1|1],id[u<<1])?id[u<<1|1]:id[u<<1];
cnt[u]=calc(u<<1|1,mid+1,r,id[u<<1]);
}
int main()
{
scanf("%d%d",&n,&q); build(1,1,n);
int p,x;
while (q--)
{
scanf("%d%d",&p,&x);
h[p]=x; modify(1,1,n,p);
printf("%d\n",calc(1,1,n,0));
}
}

平衡树

普通平衡树:

AVL 树
using namespace std;
const int N=1e5+15;
struct AVLTree
{
private:
struct Node{int l,r,val,height,size;}avl[N];
int cnt,root;
inline void newnode(int &now,int val){avl[now=++cnt].val=val; avl[cnt].size=1;}
inline void update(int now)
{
avl[now].size=avl[avl[now].l].size+avl[avl[now].r].size+1;
avl[now].height=std::max(avl[avl[now].l].height,avl[avl[now].r].height)+1;
}
inline int BF(int now){return avl[avl[now].l].height-avl[avl[now].r].height;}
inline void lrotate(int &now)
{
int r=avl[now].r; avl[now].r=avl[r].l; avl[r].l=now; now=r;
update(avl[now].l); update(now);
}
inline void rrotate(int &now)
{
int l=avl[now].l; avl[now].l=avl[l].r; avl[l].r=now; now=l;
update(avl[now].r); update(now);
}
inline void check(int &now)
{
int nf=BF(now);
if (nf>1)
{
int lf=BF(avl[now].l);
if (lf>0) rrotate(now);
else lrotate(avl[now].l),rrotate(now);
} else if (nf<-1)
{
int rf=BF(avl[now].r);
if(rf<0) lrotate(now);
else rrotate(avl[now].r),lrotate(now);
} else if (now) update(now);
}
void ins(int &now,int val)
{
if (!now) newnode(now,val);
else if(val<avl[now].val) ins(avl[now].l,val);
else ins(avl[now].r,val);
check(now);
}
int find(int &now,int fa)
{
int ret;
if (!avl[now].l){ret=now; avl[fa].l=avl[now].r;}
else{ret=find(avl[now].l,now); check(now);}
return ret;
}
void del(int &now,int val)
{
if (val==avl[now].val)
{
int l=avl[now].l,r=avl[now].r;
if (!l||!r) now=l+r;
else
{
now=find(r,r);
if (now!=r) avl[now].r=r;
avl[now].l=l;
}
}
else if (val<avl[now].val) del(avl[now].l,val);
else del(avl[now].r,val);
check(now);
}
public:
inline void ins(int val){ins(root,val);}
inline void del(int val){del(root,val);}
int getrank(int val)
{
int now=root,rank=1;
while (now)
{
if (val<=avl[now].val) now=avl[now].l;
else{rank+=avl[avl[now].l].size+1; now=avl[now].r;}
} return rank;
}
int getval(int rank)
{
int now=root;
while (now)
{
if (avl[avl[now].l].size+1==rank) break;
else if (avl[avl[now].l].size>=rank) now=avl[now].l;
else{rank-=avl[avl[now].l].size+1; now=avl[now].r;}
} return avl[now].val;
}
inline int pre(int x){return getval(getrank(x)-1);}
inline int nxt(int x){return getval(getrank(x+1));}
}BST;
Splay

Zig-Zag:

using namespace std;
const int N=1e5+15;
struct ZigZag_SplayTree
{
private:
struct Node{int l,r,val,size,cnt;}spl[N];
int cnt,root;
inline void newnode(int& now,int& val){spl[now=++cnt].val=val; ++spl[cnt].size; ++spl[cnt].cnt;}
inline void update(int now){spl[now].size=spl[spl[now].l].size+spl[spl[now].r].size+spl[now].cnt;}
inline void zig(int& now)
{
int l=spl[now].l; spl[now].l=spl[l].r; spl[l].r=now; now=l;
update(spl[now].r); update(now);
}
inline void zag(int& now)
{
int r=spl[now].r; spl[now].r=spl[r].l; spl[r].l=now; now=r;
update(spl[now].l); update(now);
}
void Splay(int x,int& y)
{
if (x==y) return ;
int& l=spl[y].l,&r=spl[y].r;
if (x==l) zig(y);
else if(x==r) zag(y);
else
{
if (spl[x].val<spl[y].val)
{
if (spl[x].val<spl[l].val) Splay(x,spl[l].l),zig(y),zig(y);
else Splay(x,spl[l].r),zag(l),zig(y);
}
else
{
if (spl[x].val>spl[r].val) Splay(x,spl[r].r),zag(y),zag(y);
else Splay(x,spl[r].l),zig(r),zag(y);
}
}
}
inline void delnode(int now)
{
Splay(now,root);
if (spl[now].cnt>1) spl[now].size--,spl[now].cnt--;
else if (spl[root].r)
{
int p=spl[root].r;
while (spl[p].l) p=spl[p].l;
Splay(p,spl[root].r); spl[spl[root].r].l=spl[root].l; root=spl[root].r; update(root);
}
else root=spl[root].l;
}
void ins(int& now,int& val)
{
if (!now) newnode(now,val),Splay(now,root);
else if (val<spl[now].val) ins(spl[now].l,val);
else if (val>spl[now].val) ins(spl[now].r,val);
else{++spl[now].size; ++spl[now].cnt; Splay(now,root);}
}
void del(int now,int& val)
{
if (spl[now].val==val) delnode(now);
else if (val<spl[now].val) del(spl[now].l,val);
else del(spl[now].r,val);
}
public:
inline void ins(int val){ins(root,val);}
inline void del(int val){del(root,val);}
int getrank(int val)
{
int now=root,rank=1;
while (now)
{
if (spl[now].val==val){rank+=spl[spl[now].l].size; Splay(now,root); break;}
if (val<=spl[now].val) now=spl[now].l;
else{rank+=spl[spl[now].l].size+spl[now].cnt; now=spl[now].r;}
} return rank;
}
int getval(int rank)
{
int now=root;
while (now)
{
int lsize=spl[spl[now].l].size;
if (lsize+1<=rank&&rank<=lsize+spl[now].cnt){Splay(now,root); break ;}
else if (lsize>=rank) now=spl[now].l;
else{rank-=lsize+spl[now].cnt; now=spl[now].r;}
} return spl[now].val;
}
inline int pre(int x){return getval(getrank(x)-1);}
inline int nxt(int x){return getval(getrank(x+1));}
}BST;
替罪羊树
using namespace std;
const int N=1e5+15;
struct tzy
{
private:
static constexpr double alpha=0.75;
struct Node
{
int l,r,val;
int size,fact;
bool exist;
}tr[N];
int cnt,root;
inline void newnode(int &now,int val){now=++cnt; tr[now].val=val; tr[now].size=tr[now].fact=1; tr[now].exist=true;}
inline bool imbalence(int now){return (max(tr[tr[now].l].size,tr[tr[now].r].size)>tr[now].size*alpha)||
(tr[now].size-tr[now].fact>tr[now].size*0.3); }
vector<int> v;
void ldr(int now)
{
if (!now) return;
ldr(tr[now].l);
if (tr[now].exist) v.push_back(now);
ldr(tr[now].r);
}
void lift(int l,int r,int &now)
{
if (l==r){now=v[l]; tr[now].l=tr[now].r=0; tr[now].size=tr[now].fact=1; return ;}
int m=(l+r)>>1;
while ((l<m)&&(tr[v[m]].val==tr[v[m-1]].val)) --m;
now=v[m];
if (l<m) lift(l,m-1,tr[now].l);
else tr[now].l=0;
lift(m+1,r,tr[now].r);
tr[now].size=tr[tr[now].l].size+tr[tr[now].r].size+1;
tr[now].fact=tr[tr[now].l].fact+tr[tr[now].r].fact+1;
}
void rebuild(int &now)
{
v.clear(); ldr(now);
if (v.empty()){now=0; return ;}
lift(0,v.size()-1,now);
}
void update(int now,int end)
{
if (!now) return;
if (tr[end].val<tr[now].val) update(tr[now].l,end);
else update(tr[now].r,end);
tr[now].size=tr[tr[now].l].size+tr[tr[now].r].size+1;
}
void check(int &now,int end)
{
if (now==end) return;
if (imbalence(now)){rebuild(now); update(root,now); return ;}
if (tr[end].val<tr[now].val) check(tr[now].l,end);
else check(tr[now].r,end);
}
void ins(int &now,int val)
{
if (!now){newnode(now,val); check(root,now); return ;}
++tr[now].size; ++tr[now].fact;
if (val<tr[now].val) ins(tr[now].l,val);
else ins(tr[now].r,val);
}
void del(int now,int val)
{
if (tr[now].exist&&tr[now].val==val){tr[now].exist=false; tr[now].fact--; check(root,now); return ;}
tr[now].fact--;
if (val<tr[now].val) del(tr[now].l,val);
else del(tr[now].r,val);
}
public:
inline void ins(int val){ins(root,val);}
inline void del(int val){del(root,val);}
int getrank(int val)
{
int now=root,rank=1;
while (now)
{
if (val<=tr[now].val) now=tr[now].l;
else {rank+=tr[now].exist+tr[tr[now].l].fact; now=tr[now].r;}
} return rank;
}
int getval(int rank)
{
int now=root;
while (now)
{
if (tr[now].exist&&tr[tr[now].l].fact+tr[now].exist==rank) break;
else if (tr[tr[now].l].fact>=rank) now=tr[now].l;
else {rank-=tr[tr[now].l].fact+tr[now].exist; now=tr[now].r;}
} return tr[now].val;
}
inline int pre(int x){return getval(getrank(x)-1);}
inline int nxt(int x){return getval(getrank(x+1));}
}BST;
fhq-Treap
using namespace std;
const int N=1e5+15;
static mt19937 rnd(19260817);
struct fhq_treap
{
private:
struct Node{int l,r,val,size,key;}fhq[N];
int cnt,root;
inline int newnode(int val){fhq[++cnt].val=val; fhq[cnt].key=rnd(); fhq[cnt].size=1; return cnt;}
inline void update(int now){fhq[now].size=fhq[fhq[now].l].size+fhq[fhq[now].r].size+1;}
void split(int now,int val,int& x,int& y)
{
if (!now) x=y=0;
else
{
if (fhq[now].val<=val){x=now; split(fhq[now].r,val,fhq[now].r,y);}
else{y=now; split(fhq[now].l,val,x,fhq[now].l);}
update(now);
}
}
int merge(int x,int y)
{
if (!x||!y) return x+y;
if (fhq[x].key>fhq[y].key){fhq[x].r=merge(fhq[x].r,y); update(x); return x;}
else{fhq[y].l=merge(x,fhq[y].l); update(y); return y;}
return 0;
}
#define def1 static int x,y;
#define def2 static int x,y,z;
public:
inline void ins(int val){def1; split(root,val,x,y); root=merge(merge(x,newnode(val)),y);}
inline void del(int val)
{
def2;
split(root,val,x,z); split(x,val-1,x,y);
y=merge(fhq[y].l,fhq[y].r); root=merge(merge(x,y),z);
}
inline int getrank(int val){def1; split(root,val-1,x,y); int ans=fhq[x].size+1; root=merge(x,y); return ans;}
inline int getval(int rank)
{
int now=root;
while (now)
{
if (fhq[fhq[now].l].size+1==rank) break;
else if (fhq[fhq[now].l].size>=rank) now=fhq[now].l;
else{rank-=fhq[fhq[now].l].size+1; now=fhq[now].r;}
} return fhq[now].val;
}
inline int pre(int val)
{
def1;
split(root,val-1,x,y); int now=x;
while (fhq[now].r) now=fhq[now].r;
int ans=fhq[now].val; root=merge(x,y); return ans;
}
inline int nxt(int val)
{
def1;
split(root,val,x,y); int now=y;
while (fhq[now].l) now=fhq[now].l;
int ans=fhq[now].val; root=merge(x,y); return ans;
}
#undef def1
#undef def2
}BST;
Treap

SBT
using namespace std;
const int N=2e5+5;
typedef long long ll;
struct SBT
{
private:
struct node{int l,r,val,size;}sbt[N];
int cnt,root;
inline void lrotate(int& now)
{
int r=sbt[now].r;
sbt[now].r=sbt[r].l; sbt[r].l=now;
sbt[r].size=sbt[now].size; sbt[now].size=sbt[sbt[now].l].size+sbt[sbt[now].r].size+1;
now=r;
}
inline void rrotate(int& now)
{
int l=sbt[now].l;
sbt[now].l=sbt[l].r; sbt[l].r=now;
sbt[l].size=sbt[now].size; sbt[now].size=sbt[sbt[now].l].size+sbt[sbt[now].r].size+1;
now=l;
}
void maintain(int& t,bool fl)
{
if (!fl)
{
if (sbt[sbt[sbt[t].l].l].size>sbt[sbt[t].r].size) rrotate(t);
else if (sbt[sbt[sbt[t].l].r].size>sbt[sbt[t].r].size) lrotate(sbt[t].l),rrotate(t);
else return ;
}
else
{
if (sbt[sbt[sbt[t].r].r].size>sbt[sbt[t].l].size) lrotate(t);
else if (sbt[sbt[sbt[t].r].l].size>sbt[sbt[t].l].size) rrotate(sbt[t].r),lrotate(t);
else return ;
}
maintain(sbt[t].l,false); maintain(sbt[t].r,true);
maintain(t,true); maintain(t,false);
}
void ins(int& t,int& v)
{
if (t)
{
++sbt[t].size;
if (v<sbt[t].val) ins(sbt[t].l,v);
else ins(sbt[t].r,v);
maintain(t,v>=sbt[t].val);
}
else
{
++cnt; t=cnt;
sbt[t].val=v; sbt[t].size=1;
sbt[t].l=sbt[t].r=0;
}
}
int del(int& t,int v)
{
int ans=0; --sbt[t].size;
if ((v==sbt[t].val)||((v<sbt[t].val)&&!sbt[t].l)||((v>sbt[t].val)&&!sbt[t].r))
{
ans=sbt[t].val;
if (!sbt[t].l||!sbt[t].r) t=sbt[t].l+sbt[t].r;
else sbt[t].val=del(sbt[t].l,sbt[t].val+1);
return ans;
}
else
{
if (v<sbt[t].val) return del(sbt[t].l,v);
else return del(sbt[t].r,v);
}
}
bool find(int& t,int& v)
{
if (!t) return 0;
if (v<sbt[t].val) return find(sbt[t].l,v);
else return (sbt[t].val==v)||find(sbt[t].r,v);
}
int getval(int& t,int k) // recursion
{
if (k==sbt[sbt[t].l].size+1) return sbt[t].val;
if (k<=sbt[sbt[t].l].size) return getval(sbt[t].l,k);
else return getval(sbt[t].r,k-1-sbt[sbt[t].l].size);
}
int getrank(int& t,int& v) // recursion
{
if (!t) return 1;
if (v<=sbt[t].val) return getrank(sbt[t].l,v);
else return sbt[sbt[t].l].size+1+getrank(sbt[t].r,v);
}
public:
SBT(){cnt=root=0; sbt[0].size=0;}
inline void ins(int val){ins(root,val);}
inline void del(int val){del(root,val);}
inline int getval(int rk){return getval(root,rk);}
inline int getrank(int val){return getrank(root,val);}
inline int pre(int x){return getval(getrank(x)-1);}
inline int nxt(int x){return getval(getrank(x+1));}
}BST;
vector
using namespace std;
struct VectorTree
{
private:
vector<ll> v;
public:
#define LWBp lower_bound(v.begin(),v.end(),val) // pointer
#define LWB LWBp-v.begin() // value
inline void clear(){v.clear();}
VectorTree(){clear();}
inline void ins(ll val){v.insert(LWBp,val);}
inline void del(ll val){v.erase(LWBp,LWBp+1);}
inline int getrank(ll val){return LWB+1;}
inline ll getval(unsigned rk){return v[rk-1];}
inline ll pre(ll x){return getval(getrank(x)-1);}
inline ll nxt(ll x){return getval(getrank(x+1));} // suf
inline size_t size(){return v.size();}
#undef LWBp
#undef LWB
}BST;

文艺平衡树:

Splay

const int N = 3e5+500;
int n, m, val[N];
struct Splay
{
int root, fa[N], ch[N][2], siz[N], lazy[N], cc;
inline void pushup(int u){siz[u] = siz[ch[u][0]] + siz[ch[u][1]] + 1;}
inline bool son(int u){return u == ch[fa[u]][1];}
inline void rotate(int x)
{
int y = fa[x], z = fa[y], chk = son(x);
ch[z][son(y)] = x; fa[x] = z;
ch[y][chk] = ch[x][chk^1]; fa[ch[x][chk^1]] = y;
ch[x][chk^1] = y; fa[y] = x;
pushup(y); pushup(x);
}
inline void splay(int x, int to = 0)
{
while (fa[x] != to)
{
int y = fa[x];
if (fa[y] != to) rotate(son(y) == son(x) ? y : x);
rotate(x);
} if (!to) root = x;
}
inline void pushdown(int x)
{
if (lazy[x])
{
lazy[ch[x][0]] ^= 1; lazy[ch[x][1]] ^= 1;
swap(ch[x][0], ch[x][1]);
lazy[x] = 0;
}
}
inline void insert(int k)
{
int x = root, f = 0;
while (x && (k != val[x])){f = x; x = ch[x][k > val[x]];}
x = ++cc;
if (f) ch[f][k > val[f]] = x;
fa[x] = f; ch[x][0] = ch[x][1] = lazy[x] = 0;
siz[x] = 1; val[x] = k;
splay(x);
}
inline int kth(int k)
{
int x = root;
while (true)
{
pushdown(x);
if (k > siz[ch[x][0]] + 1){k -= siz[ch[x][0]] + 1; x = ch[x][1];}
else if (k <= siz[ch[x][0]]) x = ch[x][0];
else return x;
}
}
inline void reverse(int l, int r)
{
int p = kth(l-1), s = kth(r+1);
splay(p); splay(s, p);
lazy[ch[s][0]] ^= 1;
}
inline void ldr(int x)
{
if (!x) return ;
pushdown(x);
ldr(ch[x][0]);
if ((val[x] > 1) && (val[x] < n+2)) printf("%d ", val[x]-1);
ldr(ch[x][1]);
}
Splay(){root = cc = 0;}
}T;
// T.reverse(l+1, r+1)
fhq-Treap
const int N=1e5+15;
static mt19937 rnd(19260817);
struct revfhq
{
private:
struct Node{int l,r,val,size; bool reversed;}fhq[N];
int cnt,root;
inline int newnode(int val){fhq[++cnt].val=val; fhq[cnt].size=1; fhq[cnt].reversed=false; return cnt;}
inline void update(int now){fhq[now].size=fhq[fhq[now].l].size+fhq[fhq[now].r].size+1;}
inline void pushdown(int now)
{
swap(fhq[now].l,fhq[now].r);
fhq[fhq[now].l].reversed^=1; fhq[fhq[now].r].reversed^=1;
fhq[now].reversed=false;
}
void split(int now,int siz,int &x,int &y)
{
if (!now) x=y=0;
else
{
if (fhq[now].reversed) pushdown(now);
if (fhq[fhq[now].l].size<siz){x=now; split(fhq[now].r,siz-fhq[fhq[now].l].size-1,fhq[now].r,y);}
else{y=now; split(fhq[now].l,siz,x,fhq[now].l);}
update(now);
}
}
int merge(int x,int y)
{
if(!x||!y) return x+y;
if (int(rnd())%(fhq[x].size+fhq[x].size)<fhq[x].size)
{
if (fhq[x].reversed) pushdown(x);
fhq[x].r=merge(fhq[x].r,y); update(x); return x;
}
else
{
if (fhq[y].reversed) pushdown(y);
fhq[y].l=merge(x,fhq[y].l); update(y); return y;
}
return 0;
}
public:
inline void reverse(int l,int r)
{
static int x,y,z;
split(root,l-1,x,y); split(y,r-l+1,y,z);
fhq[y].reversed^=1; root=merge(merge(x,y),z);
}
inline void ldr(int now)
{
if (!now) return ;
if (fhq[now].reversed) pushdown(now);
ldr(fhq[now].l); printf("%d ",fhq[now].val); ldr(fhq[now].r);
}
inline void ldr(){ldr(root);}
inline void insLE(int i){root=merge(root,newnode(i));}
}BST;

二逼平衡树:

珂朵莉树 (ODT)

k-D Tree

动态树

持久化数据结构

动态规划

背包 DP

多项式

多项式乘法

计算几何

其他问题

高精度

正整数高精

整数高精

浮点数高精

此题 附件 .

浮点数高精 - plus

int128

偏序

三维偏序

CDQ 分治
using namespace std;
const int N=2e5+500;
typedef long long ll;
int n,m,k,cnt[N],ans[N];
struct Node{int a,b,c;}a[N];
struct Answer{int a,b,c,cnt,ans;}b[N];
template<typename T>
struct FenwickTree{/*这里应有一个树状数组*/};
FenwickTree<int> e;
bool cmp1(const Node& x,const Node& y)
{
if (x.a==y.a)
{
if (x.b==y.b) return x.c<y.c;
return x.b<y.b;
} return x.a<y.a;
}
bool cmp2(const Answer& x,const Answer& y)
{
if (x.b==y.b) return x.c<y.c;
return x.b<y.b;
}
void cdq(int l,int r)
{
if (l==r) return ;
int mid=(l+r)>>1;
cdq(l,mid); cdq(mid+1,r);
sort(b+l,b+mid+1,cmp2);
sort(b+mid+1,b+r+1,cmp2);
int j=l;
for (int i=mid+1;i<=r;i++)
{
while ((b[i].b>=b[j].b)&&(j<=mid)){e.add(b[j].c,b[j].cnt); ++j;}
b[i].ans+=e.query(b[i].c);
}
for (int i=l;i<j;i++) e.add(b[i].c,-b[i].cnt);
}
int main()
{
scanf("%d%d",&n,&k); e.resize(k);
for (int i=1;i<=n;i++) scanf("%d%d%d",&a[i].a,&a[i].b,&a[i].c);
sort(a+1,a+1+n,cmp1);
int cc=0;
for (int i=1;i<=n;i++)
{
++cc;
if ((a[i].a!=a[i+1].a)||(a[i].b!=a[i+1].b)||(a[i].c!=a[i+1].c))
{
++m;
b[m].a=a[i].a; b[m].b=a[i].b; b[m].c=a[i].c;
b[m].cnt=cc; cc=0;
}
}
cdq(1,m);
for (int i=1;i<=m;i++) ans[b[i].ans+b[i].cnt-1]+=b[i].cnt;
for (int i=0;i<n;i++) printf("%d\n",ans[i]);
return 0;
}
k-D Tree

bitset

悬线法

矩形面积并

自适应辛普森积分

自适应辛普森积分

牛顿迭代

牛迭

模拟退火 (SA)

SA

Fibonacci 数列

统一了线性递推的简单做法

递推

矩阵快速幂

扩域

斐波那契循环节

邪门算法

Dancing Links (DLX)

Berlekamp-Massey 算法 (BM)

动态图连通性

模板库 ~ Template library的更多相关文章

  1. 35.自己实现vector模板库myvector

    myvector.h #pragma once //自己写的vector模板库 template <class T> class myvector { public: //构造 myvec ...

  2. C++标准模板库Stand Template Library(STL)简介与STL string类

    参考<21天学通C++>第15和16章节,在对宏和模板学习之后,开启对C++实现的标准模板类STL进行简介,同时介绍简单的string类.虽然前面对于vector.deque.list等进 ...

  3. STL标准模板库(简介)

    标准模板库(STL,Standard Template Library)是C++标准库的重要组成部分,包含了诸多在计算机科学领域里所常见的基本数据结构和基本算法,为广大C++程序员提供了一个可扩展的应 ...

  4. 【转】C++标准库和标准模板库

    C++强大的功能来源于其丰富的类库及库函数资源.C++标准库的内容总共在50个标准头文件中定义.在C++开发中,要尽可能地利用标准库完成.这样做的直接好处包括:(1)成本:已经作为标准提供,何苦再花费 ...

  5. 模板(Template)

    最近阅读google chromium base container stack_container代码,深刻感觉到基础知识不扎实. // Casts the buffer in its right ...

  6. C++ Standard Template Library STL(undone)

    目录 . C++标准模版库(Standard Template Library STL) . C++ STL容器 . C++ STL 顺序性容器 . C++ STL 关联式容器 . C++ STL 容 ...

  7. c++模板库(简介)

    目 录 STL 简介 ......................................................................................... ...

  8. 【c++】标准模板库STL入门简介与常见用法

    一.STL简介 1.什么是STL STL(Standard Template Library)标准模板库,主要由容器.迭代器.算法.函数对象.内存分配器和适配器六大部分组成.STL已是标准C++的一部 ...

  9. STL 简介,标准模板库

    这篇文章是关于C++语言的一个新的扩展--标准模板库的(Standard Template Library),也叫STL.  当我第一次打算写一篇关于STL的文章的时候,我不得不承认我当时低估了这个话 ...

随机推荐

  1. 操作系统实现-printk

    博客网址:www.shicoder.top 微信:18223081347 欢迎加群聊天 :452380935 这一次我们来实现最基础,也是最常见的函数print,大家都知道这个是可变参数函数,那具体怎 ...

  2. 153. Find Minimum in Rotated Sorted Array - LeetCode

    Question 153. Find Minimum in Rotated Sorted Array Solution 题目大意:给一个按增序排列的数组,其中有一段错位了[1,2,3,4,5,6]变成 ...

  3. 单例模式与pickle模块

    目录 设计模式之单例模式 pickle模块 设计模式之单例模式 设计模式是前辈们发明的经过反复验证用于解决固定问题的固定套路,在IT行业中设计模式总共有23种,可以分为三大类:创建型.结构型.行为型. ...

  4. 网易数帆 Envoy Gateway 实践之旅:坚守 6 年,峥嵘渐显

    服务网格成熟度不断提升,云原生环境下流量处理愈发重要, Envoy Gateway 项目于近日宣布开源,"旨在大幅降低将 Envoy 作为 API 网关的使用门槛",引发了业界关注 ...

  5. 前端CSS3布局display:grid用法

    前端CSS3布局display:flex用法 1. 先附上代码 点击查看代码 <!DOCTYPE html> <html> <head> <meta char ...

  6. Python报错 ImportError: DLL load failed while importing win32api: %1 不是有效的 Win32 应用程序 的解决方法

    今天在用jupyter notebook 的时候发生了kernel error,点开之后提示了以下报错信息 Traceback (most recent call last): File " ...

  7. 深入C++05:运算符重载

    运算符重载 1.复数类 运算符重载目的:使对象运算表现得和编译器内置类型一样: 复数类例子 #include<iostream> using namespace std; class CC ...

  8. 优先队列STL

    引入 优先队列是一种特殊的队列,它的功能是--自动排序. 基本操作: q.size(); //返回q里元素个数 q.empty(); //返回q是否为空,空则返回1,否则返回0 q.push(k); ...

  9. ExtJS 布局-Column布局(Column layout)

    更新记录: 2022年6月1日 开始. 2022年6月4日 发布. 1.说明 使用列布局,可以将容器拆分为特定大小的列,并将子组件放置在这些列中. 可以设置子组件宽度值为: 百分比(相对父容器宽度) ...

  10. tomcat 的安全配置预防后台被攻击

    安全是系统架构中最重要的关注点之一,通常情况下,所说的安全涵盖网络安全.数据安全.操作系统安全.服务器安全以及应用系统安全等诸多方面. Tomcat 是一个免费的开放源代码 的Web应用服务器,技术先 ...