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. 『忘了再学』Shell基础 — 15、环境变量(三)

    目录 1.LANG语系变量介绍 2.如何查看Linux中支持的语系 3.查看当前系统的语系 4.总结 提示: 在Linux系统中,环境变量分为两种.一种是用户自定义的环境变量,另一种是系统自带的环境变 ...

  2. Sentinel介绍与使用 收藏起来

    点赞再看,养成习惯,微信搜索[牧小农]关注我获取更多资讯,风里雨里,小农等你,很高兴能够成为你的朋友. 项目源码地址:公众号回复 sentinel,即可免费获取源码 前言 在家休息的的时候,突然小勇打 ...

  3. Android shape与selector标签使用

    原文地址:Android shape与selector标签使用 Android中提供一种xml的方式,让我们可以自由地定义背景,比较常用的就是shape标签和selector标签 shape shap ...

  4. 安装Sonarqube到CentOS(YUM)

    SonarQube 是一个用于代码质量管理的开源平台,用于管理源代码的质量. 通过插件形式,可以支持包括 java, C#, C/C++, PL/SQL, Cobol, JavaScrip, Groo ...

  5. Base64 编码知识,一文打尽!

    现在网站为了提升用户的浏览体验越来越多的使用了图片,而这些图片通常以 Base64 的形式存储和加载.因此各位开发工程师肯定对 Base64 毫不陌生了,那么你知道 Base64 究竟是什么,为什么要 ...

  6. drools执行完某个规则后终止别的规则执行

    目录 1.背景 2.需求 3.实现方案 1.通过Fact判断 2.通过全局变量判断 3.通过halt方法 4.实现上述需求 4.1 drl 文件编写 4.2 运行结果 5.完整代码 1.背景 在我们开 ...

  7. Unity中通过深度优先算法和广度优先算法打印游戏物体名

    前言:又是一个月没写博客了,每次下班都懒得写,觉得浪费时间.... 深度优先搜索和广度优先搜索的定义,网络上已经说的很清楚了,我也是看了网上的才懂的,所以就不在这里赘述了.今天讲解的实例,主要是通过自 ...

  8. Go微服务框架go-kratos实战02:proto 代码生成和编码实现步骤

    在上一篇 kratos quickstart 文章中,我们直接用 kratos new 命令生成了一个项目. 这一篇来看看 kratos API 的定义和使用. 一.kratos 中 API 简介 1 ...

  9. PyTorch保存模型、冻结参数等

    此外可以参考PyTorch模型保存.https://zhuanlan.zhihu.com/p/73893187 查看模型每层输出详情 Keras有一个简洁的API来查看模型的每一层输出尺寸,这在调试网 ...

  10. React中render Props模式

    React组件复用 React组件复用的方式有两种: 1.render Props模式 2.高阶组件HOC 上面说的这两种方式并不是新的APi. 而是利用Raect自身的编码特点,演化而来的固定编码写 ...