为了以后方便用,可以从这里粘
为了简短没有定义数组等,但需要注意的初始化都已标出
可使用Templates_NOIP或右侧目录
纯属个人向
持续更新中

数 论 数论 数论

数论太大了,学不完

gcd

int gcd(int a, int b) {return !b ? a : gcd(b, a % b);}

exgcd求逆元

Templates_NOIP_02,适用于求个数不多逆元但模数很大且是素数时

void exgcd(ll a, ll b, ll &d, ll &x, ll &y) {
if (!b) d = a, x = 1, y = 0;
else exgcd(b, a % b, d, y, x), y -= x * (a / b);
}
ll Inv(ll a, ll p) {
ll d, x, y;
exgcd(a, p, d, x, y);
return d == 1 ? (x + p) % p : -1;
}

费马小定理/欧拉定理求逆元

Templates_CSP_03,适用于模数是质数时

ll fpow(ll a, ll b, ll mod, ll ans = 1) {
while (b) {
if (b & 1) ans = ans * a % mod;
a = a * a % mod; b >>= 1;
}
return ans;
}
ll Inv(ll a,ll mod) {return fpow(a, mod - 2, mod);}

递归求逆元

Templates_CSP_03,适用于模数是质数时

ll inv(ll x) {
if (x == 1) return 1;
return (mod - mod / x) * inv(mod % x) % mod;
}

线性求逆元

适用于模数是质数时

void Inv(LL mod) {
inv[1] = 1;
for (int i = 2; i < mod; i++)
inv[i] = (mod - mod / i) * inv[mod % i] % mod;
}

递推求组合数

for (int i = 0; i <= A; i++) c[i][0] = 1; 
for (int i = 1; i <= A; i++)
for (int j = 1; j <= A; j++)
c[i][j] = (c[i - 1][j] + c[i - 1][j - 1]) % mod;

卢卡斯定理求组合数

适用于Templates_中国剩余定理_05很大但模数比较小且是质数时

void init(ll mod) {
fac[0] = 1;
for (int i = 1; i <= p; i++) fac[i] = fac[i - 1] * i % mod;
}
ll fpow(ll a, ll b, ll mod, ll ans = 1) {
a %= m;
while (b) {
if (b & 1) ans = ans * a % mod;
a = a * a % mod;
b >>= 1;
}
return ans;
}
ll inv(ll x, ll mod) {return fpow(x, mod - 2, mod);}
ll C(ll n, ll m, ll mod) {
if (m > n) return 0;
return fac[n] * inv(fac[m] * fac[n - m], mod) % mod;
}
ll Lucas(ll n, ll m, ll mod) {
if (m == 0) return 1;
return C(n % mod, m % mod, mod) * Lucas(n / mod, m / mod, mod) % mod;
}

当然还有扩展卢卡斯定理处理模数不是质数时,扩展卢卡斯就是结合了一下中国剩余定理解一些同余方程组

质因子分解求组合数

模数不是质数时可以用这个方法,但基本没有专门用这个解法的题
Templates_i++_06的问题上面的几种方法都可以解决

void prime() {
for (int i = 2; i <= maxn; i++) {
if (!pri[i]) pri[++pri[0]] = i;
for (int j = 1; j <= pri[0] and i * pri[j] <= maxn; j++) {
pri[pri[j] * i] = 1;
if (i % pri[j] == 0) break;
}
}
}
void factor_jc(int n) {
int i, t = n;
if (t < 0) t = -t;
for (i = 1; i <= pri[0] and pri[i] <= t; i++) {
int tmp = n;
while (tmp) fac[i] += tmp / pri[i], tmp /= pri[i];
}
fac[0] = max(fac[0], i);
}
ll fpow(ll a, ll b, ll ans = 1) {
while (b) {
if (b & 1) ans = ans * a % mod;
a = a * a % mod; b >>= 1;
}
return ans;
}
ll C(int n, int m) {
memset(fac, 0, sizeof fac);
factor_jc(n); factor_jc(-m); factor_jc(m - n);
ll ans = 1;
for (int i = 1; i < fac[0]; i++) if (fac[i])
ans = ans * fpow(pri[i], fac[i]) % mod;
return ans;
}

中国剩余定理

解同余方程组

ll exgcd(ll l, ll r, ll &x, ll &y) {
if (r == 0) {x = 1; y = 0; return l;}
else {
ll d = exgcd(r, l % r, y, x);
y -= l / r * x;
return d;
}
}
ll china(ll n, ll *a, ll *m) {
ll mod = 1, y, x = 0, d;
for (int i = 1; i <= n; i++) mod *= m[i];
for (int i = 1; i <= n; i++) {
ll w = mod / m[i];
exgcd(m[i], w, d, y);
x = (x + y * w * a[i]) % mod;
}
return (x + mod) % mod;
}

扩展中国剩余定理

适用于同余方程组模数不互质时

ll exgcd(ll a, ll b, ll &x, ll &y) {
if (!b) {x = 1, y = 0; return a;}
ll re = exgcd(b, a % b, x, y), tmp = x;
x = y, y = tmp - (a / b) * y;
return re;
}
ll multi(ll a, ll b, ll mod, ll ans = 0) {
while (b) {
if (b & 1) ans = (ans + a) % mod;
a = (a + a) % mod;
b >>= 1;
}
return ans;
}
ll work() {
ll M = m[1], A = a[1], t, d, x, y;
for (int i = 2; i <= n; i++) {
d = exgcd(M, m[i], x, y);
if ((a[i] - A) % d) return -1;
x = x * (a[i] - A) / d;
t = m[i] / d, x = (x % t + t) % t;
A = M * x + A, M = M / d * m[i], A %= M;
}
A = (A % M + M) % M;
return A;
}

快速幂

ll fpow(ll a, ll b, ll mod, ll ans = 1) {
while (b) {
if (b & 1) ans = ans * a % mod;
a = a * a % mod; b >>= 1;
}
return ans;
}

线性筛 素数&&欧拉函数

int pri[A], phi[A], cnt; bool bz[A];
for (int i = 2; i <= n; i++) {
if (!bz[i]) pri[++cnt] = i, phi[i] = i - 1;
for (int j = 1; j <= cnt; j++) {
if (i * pri[j] > n) break;
bz[i * pri[j]] = 1;
if (i % pri[j] != 0) phi[i * pri[j]] = phi[i] * (pri[j] - 1);
else {phi[i * pri[j]] = phi[i] * pri[j]; break;}
}
}

求一个数的因子和

ll facsum(ll s) {
ll ans = 1; int kj = sqrt(1.0 * s);
for (int i = 0; bz[i] < kj; i++)
if (s % bz[i] == 0) {
int sum = 0;
while (s % bz[i] == 0) sum++, s /= bz[i];
ans *= (fpow(bz[i], sum + 1) - 1) * (bz[i] - 1);
}
if (s > 1) ans *= (s * s - 1) / (s - 1);
return ans;
}

求单个数的欧拉函数

ll Eular(ll x) {
ll ans = 1;
for (ll i = 2; i * i <= x; i++)
if (x - floor(x / i) * i == 0) {
x /= i;
ans *= i - 1;
while (x - floor(x / i) * i == 0) x /= i, ans *= i;
}
if (x > 1) ans *= x - 1;
return ans;
}

高斯消元

#define
#define
double a[A][A], b[A], ans[A]; int n;
int check(double x) {
if (fabs(x) <= exp) return 0;
if (x > 0) return 1;
else return -1;
}

int main(int argc, char const *argv[]) {
scanf("%d", &n);
for (int i = 1; i <= n; i++)
for (int j = 1; j <= n + 1; j++)
scanf("%lf", &a[i][j]);
for (int i = 1; i <= n; i++) {
if (!check(a[i][i])) return puts("No Solution"), 0;
int k = i;
for (int j = i; j <= n; j++) if (fabs(a[j][i]) > fabs(a[k][i])) k = j;
for (int j = 1; j <= n + 1; j++) swap(a[i][j], a[k][j]);
for (int j = i + 1; j <= n; j++)
for (int l = 1; l <= n + 1; l++)
a[j][l] -= a[i][l] * a[j][i] / a[i][i];
}
for (int i = n; i >= 1; i--) {
for (int j = n; j > i; j--) {
if (!check(a[i][j])) break;
a[i][n + 1] -= ans[j] * a[i][j];
}
ans[i] = a[i][n + 1] / a[i][i];
}
for (int i = 1; i <= n; i++) printf("%.2lf\n", ans[i]);
}

Catalan数

实例:

  • 通过不相交的对角线将Templates_中国剩余定理_07边形分割成若干三角形
  • Templates_中国剩余定理_07个节点的二叉树共有多少棵
  • 一个栈(无穷大)的进栈序列为Templates_NOIP_09,有多少个不同的出栈序列
  • 给定Templates_中国剩余定理_07对括号,求括号正确配对的字符串数
  • Templates_中国剩余定理_11的方格地图中,从一个角到另外一个角,不跨越对角线的路径数
  • 圆桌周围有Templates_i++_12个人,他们两两握手,但没有交叉的方案数

前几项:1,2,5,14,42,132,429,1430,4862,16796

f[0] = 1; f[1] = 1;
for (int i = 2; i <= n; i++)
for (int j = 0; j < i; j++)
f[i] += f[j] * f[i - j - 1];

错排公式

f[i] = (i - 1) * (f[i - 1] + f[i - 2]);

Miller_Rabin大质数判断法

const int S = 10;
ll fmod(ll a, ll b, ll c) {
a %- c; b %= c; ll ans = 0, tmp = a;
while (b) {
if (b & 1) {
ans += tmp;
if (ans > c) ans -= c;
}
tmp <<= 1;
if (tmp > c) tmp -= c;
b >>= 1;
}
return ans;
}
ll fpow(ll a, ll b, ll mod) {
ll ans = 1, tmp = a % mod;
while (b) {
if (b & 1) ans = fmod(ans, tmp, mod);
tmp = fmod(tmp, tmp, mod); b >>= 1;
}
return ans;
}
bool check(ll a, ll n, ll x, ll t) {
ll ans = fpow(a, x, n); ll last = ans;
for (int i = 1; i <= t; i++) {
ans = fmod(ans, ans, n);
if (ans == 1 and last != 1 and last != n - 1) return true;
last = ans;
}
if (ans != 1) return true;
else return false;
}
bool MR(ll n) {
if (n < 2) return false;
if (n == 2) return true;
if ((n & 1) == 0) return false;
ll x = n - 1, t = 0;
while ((x & 1) == 0) x >>= 1, t++;
srand(time(NULL));
for (int i = 0; i < S; i++) {
ll a = rand() % (n - 1) + 1;
if (check(a, n, x, t)) return false;
}
return true;
}

待填:FFT,BSGS, pollard_rho,莫比乌斯反演,自适应simpson积分,原根,Polya定理

图 论 图论 图论

标准版SPFA

void SPFA(int s) {
memset(dis, 0x3f, sizeof dis);
queue<int> q; dis[s] = 0; q.push(s);
while (!q.empty()) {
int fr = q.front(); q.pop(); vis[fr] = 0;
for (int i = head[fr]; i; i = edge[i].next) {
int ca = edge[i].to;
if (dis[ca] > dis[fr] + edge[i].dis) {
dis[ca] = dis[fr] + edge[i].dis;
if (!vis[ca]) vis[ca] = 1, q.push(ca);
}
}
}
}

SPFA SLF优化

void SPFA(int s) {
memset(dis, 0x3f, sizeof dis);
deque<int> q; dis[s] = 0; q.push_back(s);
while (!q.empty()) {
int fr = q.front(); q.pop_front(); vis[fr] = 0;
for (int i = head[fr]; i; i = e[i].next) {
int ca = e[i].to;
if (dis[ca] > dis[fr] + e[i].dis) {
dis[ca] = dis[fr] + e[i].dis;
if (!vis[ca]) {
vis[ca] = 1;
if (q.empty() or dis[ca] > dis[q.front()]) q.push_back(ca);
else q.push_front(ca);
}
}
}
}
}

SPFA LLL优化

个人感觉不如SLF实用

void SPFA(int s) {
memset(dis, 0x3f, sizeof dis);
deque<int> q; dis[s] = 0; q.push_back(s); tot = 0;
while (!q.empty()) {
int fr = q.front(); q.pop_front();
vis[fr] = 0; tot--; sum -= dis[fr];
for (int i = head[fr]; i; i = edge[i].next) {
int ca = edge[i].to;
if (dis[ca] > dis[fr] + edge[i].dis) {
dis[ca] = dis[fr] + edge[i].dis;
if (!vis[ca]) {
vis[ca] = 1;
if (q.empty() or dis[ca] * tot <= sum) q.push_back(ca);
else q.push_front(ca);
tot++; sum += dis[ca];
}
}
}
}
}

堆优化Dijkstra

struct STA {
long long w; int id;
STA() {w = 0x3f3f3f3f;}
bool operator < (const STA &a)const {return w > a.w;}
}sta[maxn];
void Dijkstra(int s) {
for (int i = 1; i <= n; i++) sta[i].id = i;
priority_queue<STA> q; sta[s].w = 0; q.push(sta[s]);
while (!q.empty()) {
int fr = q.top().id; q.pop(); vis[fr] = 1;
for (int i = head[fr]; i; i = e[i].next) {
int ca = e[i].to;
if (sta[ca].w > sta[fr].w + e[i].w) {
sta[ca].w = sta[fr].w + e[i].w;
q.push(sta[ca]);
}
}
}
}

Dinic

int num = 1; //!!!!!!!!!!!!
bool bfs() {
memset(dep, 0x3f, sizeof dep);
memset(vis, 0, sizeof vis);
queue<int> q;
dep[S] = 0; q.push(S); vis[S] = 1;
while (!q.empty()) {
int fr = q.front(); q.pop(); vis[fr] = 0;
for (int i = head[fr]; i; i = e[i].next) {
int ca = e[i].to;
if (dep[ca] > dep[fr] + 1 and e[i].w) {
dep[ca] = dep[fr] + 1;
if (!vis[ca]) {
q.push(ca);
vis[ca] = 1;
}
}
}
}
return dep[T] != 0x3f3f3f3f;
}
int dfs(int fr, int flow, int now = 0) {
if (fr == T) return flow;
for (int &i = cur[fr]; i; i = e[i].next) {
int ca = e[i].to;
if (e[i].w and dep[ca] == dep[fr] + 1) {
now = dfs(ca, min(flow, e[i].w));
if (now) {
e[i].w -= now;
e[i ^ 1].w += now;
return now;
}
}
}
return 0;
}
int dinic(int ans = 0) {
while (bfs()) {
memcpy(cur, head, sizeof head);
while (int t = dfs(S, 0x3f3f3f3f)) ans += t;
}
return ans;
}

EK

int num = 1;//!!!!!!!!!!!!!
int SPFA() {
memset(flow, 0x7f, sizeof flow);
memset(last, -1, sizeof last);
queue<int> q; q.push(S); pre[T] = -1;
while (!q.empty()) {
int fr = q.front(); q.pop();
for (int i = head[fr]; ~i; i = e[i].next) {
int ca = e[i].to;
if (e[i].w > 0 and last[ca] == -1) {
pre[ca] = fr; last[ca] = i;
flow[ca] = min(flow[fr], e[i].w);
q.push(ca);
}
}
}
return pre[T] != -1;
}
int EK() {
int ans = 0;
while (SPFA()) {
int fr = T; ans += flow[T];
while (fr != S) {
e[last[fr]].w -= flow[T];
e[last[fr] ^ 1].w += flow[T];
fr = pre[fr];
}
}
return ans;
}

ISAP

int num = 1;//!!!!!!!!!!!!!
void bfs() {
memset(dep, -1, sizeof dep);
memset(gap, 0, sizeof gap);
queue<int> q;
q.push(T); dep[T] = 0; gap[0] = 1;
while (!q.empty()) {
int fr = q.front(); q.pop();
for (int i = head[fr]; i; i = e[i].next) {
int ca = e[i].to;
if (dep[ca] != -1) continue;
q.push(ca);
dep[ca] = dep[fr] + 1;
gap[dep[ca]]++;
}
}
}
int dfs(int fr, int flow, int used = 0) {
if (fr == T) {
maxflow += flow;
return flow;
}
for(int &i = cur[fr]; i; i = e[i].next) {
int ca = e[i].to;
if (e[i].w and dep[ca] + 1 == dep[fr]) {
int diss = dfs(ca, min(e[i].w, flow - used));
if (diss) {
e[i].w -= diss;
e[i ^ 1].w += diss;
used += diss;
}
if (used == flow) return used;
}
}
if (!--gap[dep[fr]]) dep[S] = n + 1;
dep[fr]++; gap[dep[fr]]++;
return used;
}
int ISAP() {
maxflow = 0;
bfs();
while (dep[S] < n) {
memcpy(cur, head, sizeof head);
dfs(S, inf);
}
return maxflow;
}

HLPP

int num = 1;//!!!!!!!!!!!!!!
struct cmp {
bool operator () (int a, int b) const {return h[a] < h[b];}
};
queue<int> q;
priority_queue<int, vector<int>, cmp> qq;
bool bfs() {
memset(h, 0x3f, sizeof h);
h[T] = 0; q.push(T);
while (!q.empty()) {
int fr = q.front(); q.pop();
for (int i = head[fr]; ~i; i = e[i].next) {
int ca = e[i].to;
if (h[ca] > h[fr] + 1 and e[i ^ 1].w) h[ca] = h[fr] + 1, q.push(ca);
}
}
return h[S] != 0x3f3f3f3f;
}
void push(int fr) {
for (int i = head[fr]; ~i; i = e[i].next) {
int ca = e[i].to;
if (e[i].w and h[ca] + 1 == h[fr]) {
int diss = min(prs[fr], e[i].w);
e[i].w -= diss; e[i ^ 1].w += diss;
prs[fr] -= diss; prs[ca] += diss;
if (ca != S and ca != T and !vis[ca]) vis[ca] = 1, qq.push(ca);
if (!prs[fr]) break;
}
}
}
void relable(int fr) {
h[fr] = 0x3f3f3f3f;
for (int i = head[fr]; ~i; i = e[i].next) {
int ca = e[i].to;
if (e[i].w and h[ca] + 1 < h[fr]) h[fr] = h[ca] + 1;
}
}
void dfs(int fr, int fa) {
for (int i = head[fr]; i; i = e[i].next) {
int ca = e[i].to;
if (ca == fa) continue;
dep[ca] = dep[fr] + 1;
dfs(ca, fr);
}
}
int HLPP() {
if (!bfs()) return 0;
h[S] = n;
memset(gap, 0, sizeof gap);
for (int i = 1; i <= n; i++) if (h[i] < 0x3f3f3f3f) gap[h[i]]++;
for (int i = head[S]; ~i; i = e[i].next) {
int ca = e[i].to, diss = e[i].w;
if (diss) {
e[i].w -= diss; e[i ^ 1].w += diss;
prs[S] -= diss; prs[ca] += diss;
if (ca != S and ca != T and !vis[ca]) qq.push(ca), vis[ca] = 1;
}
}
while (!qq.empty()) {
int fr = qq.top(); qq.pop();
vis[fr] = 0; push(fr);
if (prs[fr]) {
if (!--gap[h[fr]]) for (int i = 1; i <= n; i++)
if (i != S and i != T and h[i] > h[fr] and h[i] <= n)
h[i] = n + 1;
relable(fr); ++gap[h[fr]];
qq.push(fr); vis[fr] = 1;
}
}
return prs[T];
}

倍增求LCA

void dfs(int fr, int dep) {
d[fr] = dep; vis[fr] = 1;
for (int i = head[fr]; i; i = e[i].next) {
int ca = e[i].to;
if (vis[ca]) continue;
fa[ca] = fr;
dfs(ca, dep + 1);
}
}
void init() {
dfs(s, 0);
for (int i = 1; i <= n; i++) f[i][0] = fa[i];
for (int j = 1; 1 << j <= n; j++)
for (int i = 1; i <= n; i++)
f[i][j] = f[f[i][j - 1]][j - 1];
}
int Lca(int fr, int to) {
if (d[fr] < d[to]) swap(fr, to);
for (int i = 0; i <= 19; i++)
if (((d[fr] - d[to]) >> i) % 2)
fr = f[fr][i];
for (int i = 19; i >= 0; i--)
if (f[fr][i] != f[to][i])
fr = f[fr][i], to = f[to][i];
if (fr == to) return fr;
else return fa[fr];
}

tarjan缩点、求桥

有向图和无向图的区别一般就是判断是否走到父亲
一定注意重边的影响,对无向图Templates_中国剩余定理_13影响很大
缩点:

void tarjan(int fr) {
dfn[fr] = low[fr] = ++cnt; sta[++top] = fr; vis[fr] = 1;
for (int i = head[fr]; i; i = edge[i].next) {
int ca = edge[i].to;
if (!dfn[ca]) tarjan(ca), low[fr] = min(low[ca], low[fr]);
else if (vis[ca]) low[fr] = min(low[fr], dfn[ca]);
}
if (dfn[fr] == low[fr]) {
int p; kn++;
do {
p = sta[top--]; vis[p] = 0;
bl[p] = kn;
} while (p != fr);
}
}

求割点时,在回溯回来后判断Templates_NOIP_14即可
要注意根节点的特殊情况
求桥的话去掉等号就可以

树链剖分求LCA

void prepare(int fr, int faa) {
siz[fr] = 1;
for (int i = head[fr]; i; i = edge[i].next) {
int ca = edge[i].to;
if (ca == fa[fr]) continue;
dep[ca] = dep[fr] + 1;
fa[ca] = fr;
prepare(ca, fr);
siz[fr] += siz[ca];
if (siz[son[fr]] < siz[ca]) son[fr] = ca;
}
}
void dfs(int fr, int tp) {
dfn[fr] = ++cnt; pre[cnt] = fr; top[fr] = tp;
if (!son[fr]) return;
if (son[fr]) dfs(son[fr], tp);
for (int i = head[fr]; i; i = edge[i].next) {
int ca = edge[i].to;
if (ca == fa[fr] or ca == son[fr]) continue;
dfs(ca, ca);
}
}
int lca(int x, int y) {
while (top[x] != top[y]) {
if (dep[top[x]] < dep[top[y]]) swap(x, y);
x = fa[top[x]];
}
return dep[x] < dep[y] ? x : y;
}

最小费用最大流

bool SPFA() {
memset(dis, 0x7f, sizeof dis);
memset(flow, 0x7f, sizeof flow);
memset(vis, 0, sizeof vis);
queue<int> q; q.push(S); dis[S] = 0; pre[T] = -1;
while (!q.empty()) {
int fr = q.front(); q.pop(); vis[fr] = 0;
for (int i = head[fr]; ~i; i = e[i].next) {
int ca = e[i].to;
if (e[i].flow and dis[ca] > dis[fr] + e[i].dis) {
dis[ca] = dis[fr] + e[i].dis;
pre[ca] = fr; last[ca] = i;
flow[ca] = min(flow[fr], e[i].flow);
if (!vis[ca]) vis[ca] = 1, q.push(ca);
}
}
}
return pre[T] != -1;
}
void EK() {
while (SPFA()) {
int fr = T;
maxn += flow[T]; minn += flow[T] * dis[T];
while (fr != S) {
e[last[fr]].flow -= flow[T];
e[last[fr] ^ 1].flow += flow[T];
fr = pre[fr];
}
}
}

分层图最短路

解决有限制条件的最短路问题

void spfa(int s) {
memset(dis, 0x3f, sizeof dis); memset(vis, 0, sizeof vis);
deque<int> q; dis[s] = 0; q.push_back(s);
while (!q.empty()) {
int fr = q.front(); q.pop_front(); vis[fr] = 0;
for (int i = head[fr]; i; i = edge[i].next) {
int ca = edge[i].to;
if (dis[ca] > dis[fr] + edge[i].dis) {
dis[ca] = dis[fr] + edge[i].dis;
if (!vis[ca]) {
vis[ca] = 1;
if (q.empty() or dis[ca] > dis[q.front()]) q.push_back(ca);
else q.push_front(ca);
}
}
}
}
}
void add_and_work() {
for (int i = 1; i <= m; i++) {
scanf("%d%d%d", &a, &b, &c);
add_edge(a, b, c); add_edge(b, a, c);
for (int j = 1; j <= k; j++) {
add_edge(a + (j - 1) * n, b + j * n, 0);
add_edge(b + (j - 1) * n, a + j * n, 0);
add_edge(a + j * n, b + j * n, c);
add_edge(b + j * n, a + j * n, c);
}
}
spfa(s); int ans = dis[t];
for (int i = 0; i <= k; i++) ans = min(ans, dis[t + n * i]);
}

二分图最大匹配(匈牙利算法)

bool find(int x) {
for (int i = 1; i <= m; i++)
if (f[x][i] and !vis[i]) {
vis[i] = 1;
if (!g[i] or find(g[i])) {
g[i] = x;
return true;
}
}
return false;
}
void in() {
scanf("%d%d%d", &n, &m, &e); int ans = 0, x, y;
for (int i = 1; i <= e; i++) scanf("%d%d", &x, &y), f[x][y] = 1;
for (int i = 1; i <= n; i++) {
memset(vis, 0, sizeof vis);
if (find(i)) ans++;
}
printf("%d", ans);
}

带权二分图最大匹配

建图跑费用流即可

关于二分图几个有用的结论

二分图的最大独立集 = 点的总数 – 最小点覆盖
二分图的最小点覆盖 = 最大匹配
DAG的最小路径覆盖 = 原图点数 – 拆点二分图的最大匹配

树的直径

注意Templates_i++_15做法不能求带负边权的问题,树形Templates_中国剩余定理_16可以
Templates_i++_15求法:

auto bfs = [&](int s) -> pair<int, int> {
queue<int> q; q.push(s); vis[s] = 1;
while (!q.empty()) {
int fr = q.front(); q.pop();
for (int i = head[fr]; i; i = e[i].next) {
int ca = e[i].to;
if (vis[ca]) continue;
dis[ca] = dis[fr] + e[i].w;
pre[ca] = i;
q.push(ca); vis[ca] = 1;
}
}
int maxx = 0, pos = 0;
for (int i = 1; i <= n; i++) if (dis[i] > maxx) maxx = dis[i], pos = i;
for (int i = 1; i <= n; i++) dis[i] = vis[i] = pre[i] = 0;
return make_pair(pos, maxx);
};
pair<int, int> d1 = bfs(1); pair<int, int> d2 = bfs(d1.first);

树形Templates_中国剩余定理_16求法:

void dfs(int fr, int fa) {
vis[fr] = 1;
for (int i = head[fr]; i; i = e[i].next) {
int ca = e[i].to;
if (vis[ca] or ca == fa) continue;
dfs(ca, fr);
ans = max(ans, f[fr] + f[ca] + e[i].w);
f[fr] = max(f[fr], f[ca] + e[i].w);
}
}

欧拉路&&欧拉回路

  • 对于无向图
    只有两个点的度数是Templates_模板_19,这两个点分别为起点和终点,则这个无向图存在欧拉路。
    每个点的度数都为偶数,则这个无向图存在欧拉回路。
  • 对于有向图
    有一个点的入度比出度多Templates_模板_19作为终点,还有一个点的出度比入度多Templates_模板_19作为起点,其余点的入度和出度相同,则这个有向图存在欧拉路。
    所有点的入度和出度相同,则这个有向图存在欧拉回路。

点分治(树的重心)

没什么板子,因题目而异
随便放一个:在一个树上问有多少对点它们间的距离小于等于Templates_NOIP_22

struct node {int next, to, w;}e[A];
int head[A], num;
void add(int fr, int to, int w) {
e[++num].next = head[fr]; e[num].to = to;
e[num].w = w; head[fr] = num;
}
int n, k, G, a, b, c, tot/*遍历的这棵树的大小*/, ans;
int siz[A], mx[A]/*子树大小最大值*/, dep[A], dis[A], vis[A], f[A];
void getG(int fr, int fa) { //求树的重心
mx[fr] = 0; siz[fr] = 1;
for (int i = head[fr]; i; i = e[i].next) {
int ca = e[i].to;
if (ca == fa or vis[ca]) continue;
getG(ca, fr); siz[fr] += siz[ca];
mx[fr] = max(mx[fr], siz[ca]);
}
mx[fr] = max(mx[fr], tot - siz[fr]); //父亲翻转为子树
G = mx[fr] < mx[G] ? fr : G;
}
void dfs(int fr, int fa) {
dep[++dep[0]] = f[fr];
for (int i = head[fr]; i; i = e[i].next) {
int ca = e[i].to;
if (ca == fa or vis[ca]) continue;
f[ca] = f[fr] + e[i].w;
dfs(ca, fr);
}
}
int calc(int fr, int len, int sum = 0) {
dep[0] = 0; f[fr] = len; dfs(fr, 0);
sort(dep + 1, dep + 1 + dep[0]);
for (int l = 1, r = dep[0]; l < r;)
if (dep[l] + dep[r] <= k) sum += r - l, l++;
else r--;
return sum;
}
void divide(int fr) {
ans += calc(fr, 0); vis[fr] = 1;
for (int i = head[fr]; i; i = e[i].next) {
int ca = e[i].to;
if (vis[ca]) continue;
ans -= calc(ca, e[i].w); //经过重心下面的点就统计答案,要减掉
tot = mx[0] = siz[ca]; //新树的大小,即子问题
G = 0; getG(ca, 0); divide(G);
}
}

int main(int argc, char const *argv[]) {
scanf("%d", &n);
for (int i = 1; i < n; i++) scanf("%d%d%d", &a, &b, &c), add(a, b, c), add(b, a, c);
scanf("%d", &k); tot = mx[0] = n; getG(1, 0);
divide(G); printf("%d\n", ans);
}

2-SAT

就是针对一些布尔变量的互相关系求出一组解

void tarjan(int fr) {
dfn[fr] = low[fr] = ++cnt, sta[++top] = fr, vis[fr] = 1;
for (int i = head[fr]; i; i = e[i].next) {
int ca = e[i].to;
if (!dfn[ca]) tarjan(ca), low[fr] = min(low[fr], low[ca]);
else if (vis[ca]) low[fr] = min(low[fr], dfn[ca]);
}
if (low[fr] == dfn[fr]) {
++kn; int p;
do {
p = sta[top--];
vis[p] = 0;
bl[p] = kn;
} while (p != fr);
}
}


int main(int argc, char const *argv[]) {
cin >> n >> m;
for (int i = 1; i <= m; i++) {
scanf("%d%d%d%d", &a, &b, &c, &d);
if (b and d) add(a + n, c), add(c + n, a);
if (!b and d) add(a, c), add(c + n, a + n);
if (b and !d) add(c, a), add(a + n, c + n);
if (!b and !d) add(a, c + n), add(c, a + n);
}
for (int i = 1; i <= n * 2; i++) if (!dfn[i]) tarjan(i);
for (int i = 1; i <= n; i++) if (bl[i] == bl[i + n]) return puts("IMPOSSIBLE"), 0;
puts("POSSIBLE");
for (int i = 1; i <= n; i++) printf("%d ", bl[i] < bl[i + n]);
}

字 符 串 字符串 字符串

KMP

Templates_CSP_23是子串,Templates_CSP_24是母串,在Templates_CSP_24上找Templates_CSP_23

int i = 0, j = -1; nxt[0] = -1;
while (i < len2)
if (j == -1 or s2[i] == s2[j]) nxt[++i] = ++j;
else j = nxt[j];
i = 0; j = 0;
while (i < len1) {
if (j == -1 or s1[i] == s2[j]) i++, j++;
else j = nxt[j];
if (j == len2) cout << i - len2 + 1 << endl, j = nxt[j];
}

manacher

询问Templates_CSP_27的最长回文半径

void manacher(char *s) {
int mx = -1, id = 0;
for (int i = 1; i <= lena; i++) {
if (mx > i) p[i] = min(p[id * 2 - 1], mx - i);
else p[i] = 1;
while (s[i - p[i]] == s[i + p[i]]) p[i]++;
if (i + p[i] > mx) mx = i + p[i], id = i;
}
}

AC自动机

多模式串匹配

struct node {int fail, son[26], w;}t[A];
int n, tot; char s[A];
void insert(char *s, int rt = 0) {
for (int i = 0; s[i]; i++) {
int x = s[i] - 'a';
if (!t[rt].son[x]) t[rt].son[x] = ++tot;
rt = t[rt].son[x];
}
t[rt].w++;
}
void gfail() {
queue<int> q;
for (int i = 0; i < 26; i++) if (t[0].son[i]) q.push(t[0].son[i]);
while (!q.empty()) {
int fr = q.front(); q.pop();
for (int i = 0; i < 26; i++)
if (t[fr].son[i]) {
t[t[fr].son[i]].fail = t[t[fr].fail].son[i];
q.push(t[fr].son[i]);
}
else t[fr].son[i] = t[t[fr].fail].son[i];
}
}
void acm(int rt = 0, int ans = 0) {
for (int i = 0; s[i]; i++) {
int x = s[i] - 'a'; rt = t[rt].son[x];
for (int p = rt; p and t[p].w != -1; p = t[p].fail)
ans += t[p].w, t[p].w = -1;
}
cout << ans << endl;
}
void init() {
cin >> n;
for (int i = 1; i <= n; i++) cin >> s, insert(s);
gfail(); cin >> s; acm();
}

后缀数组

处理字符串问题的利器

void SA() {
cin >> (s + 1); n = strlen(s + 1); m = 'z';
for (int i = 1; i <= n; i++) ++c[x[i] = s[i]];
for (int i = 2; i <= m; i++) c[i] += c[i - 1];
for (int i = n; i >= 1; i--) sa[c[x[i]]--] = i;
for (int k = 1; k <= n; k <<= 1) {
int num = 0;
for (int i = n - k + 1; i <= n; i++) y[++num] = i;
for (int i = 1; i <= n; i++) if (sa[i] > k) y[++num] = sa[i] - k;
memset(c, 0, sizeof c);
for (int i = 1; i <= n; i++) ++c[x[i]];
for (int i = 2; i <= m; i++) c[i] += c[i - 1];
for (int i = n; i >= 1; i--) sa[c[x[y[i]]]--] = y[i], y[i] = 0;
swap(x, y); x[sa[1]] = 1; num = 1;
for (int i = 2; i <= n; i++)
if (y[sa[i]] == y[sa[i - 1]] and y[sa[i] + k] == y[sa[i - 1] + k]) x[sa[i]] = num;
else x[sa[i]] = ++num;
if (num == n) break;
m = num;
}
}

后缀自动机

处理字符串问题的另一利器

void insert(int fr) {
int p = last, cnt = ++n; last = cnt, mx[cnt] = mx[p] + 1;
while (p and !son[p][fr]) son[p][fr] = cnt, p = fa[p];
if (!p) fa[cnt] = root;
else {
int q = son[p][fr];
if (mx[p] + 1 == mx[q]) fa[cnt] = q;
else {
int cntq = ++n; mx[cntq] = mx[p] + 1;
memcpy(son[cntq], son[q], sizeof son[q]);
fa[cntq] = fa[q], fa[cnt] = fa[q] = cntq;
while (son[p][fr] == q) son[p][fr] = cntq, p = fa[p];
}
}
siz[cnt] = 1;
}
void init() {
cin >> (s + 1); last = root = ++n; int m = strlen(s + 1);
for (int i = 1; i <= m; i++) insert(s[i] - 'a');
for (int i = 1; i <= n; i++) c[mx[i]]++;
for (int i = 2; i <= n; i++) c[i] += c[i - 1];
for (int i = 1; i <= n; i++) a[c[mx[i]]--] = i;
for (int i = n; i >= 1; i--) {
int pos = a[i];
siz[fa[pos]] += siz[pos];
if (siz[pos] > 1) ans = max(ans, (ll)siz[pos] * mx[pos]);
}
cout << ans << endl;
}

数 据 结 构 数据结构 数据结构

二维树状数组

矩阵求和修改问题

int lowbit(int x) {return x & -x;}
void add(int x, int y, ll ad) {
for (int i = x; i <= n; i += lowbit(i))
for (int j = y; j <= m; j += lowbit(j)) {
t1[i][j] += ad;
t2[i][j] += ad * x;
t3[i][j] += ad * y;
t4[i][j] += ad * x * y;
}
}
void addval(int a, int b, int c, int d, int delta) {
add(a, b, delta); add(a, d + 1, -delta);
add(c + 1, b, -delta); add(c + 1, d + 1, delta);
}
int ask(int x, int y, int ans = 0) {
for (int i = x; i; i -= lowbit(i))
for (int j = y; j; j -= lowbit(j))
ans += (x + 1) * (y + 1) * t1[i][j] - (y + 1) * t2[i][j] - (x + 1) * t3[i][j] + t4[i][j];
return ans;
}
int area(int a, int b, int c, int d) {
return ask(c, d) - ask(c, b - 1) - ask(a - 1, d) + ask(a - 1, b - 1);
}

珂朵莉树

模糊,针对区间推平修改 区间查询和随机数据

#define

using namespace std;
typedef long long ll;
const int modd = 1e9 + 7;
struct node {
int l, r; mutable ll v;
node (int L, int R = -1, ll V = 0) : l(L), r(R), v(V) {}
friend bool operator < (const node a, const node b) {
return a.l < b.l;
}
};
ll a[A], seed, vm;
int n, m, x, y;
set<node> s;
iter split(int pos) {
iter it = s.lower_bound(node(pos));
if (it != s.end() and it->l == pos) return it;
--it;
int lt = it->l, lr = it->r;
ll lv = it->v;
s.erase(it);
s.insert(node(lt, pos - 1, lv));
return s.insert(node(pos, lr, lv)).first;
}
void assign(int l, int r, ll add = 0) {
iter llc = split(l), rrc = split(r + 1);
s.erase(llc, rrc);
s.insert(node(l, r, add));
}
void add(int l, int r, ll add = 1) {
iter llc = split(l), rrc = split(r + 1);
for (; llc != rrc; llc++) llc->v += add;
}
ll kth(int l, int r, int k) {
vector<pair<ll, int> > v;
iter llc = split(l), rrc = split(r + 1);
for (; llc != rrc; llc++) v.push_back(pair<ll, int>(llc->v, llc->r - llc->l + 1));
sort(v.begin(), v.end());
for (vector<pair<ll, int> >::iterator it = v.begin(); it != v.end(); it++) {
k -= it->second;
if (k <= 0) return it->first;
}
return -1LL;
}
ll fpow(ll a, ll b, ll mod) {
ll ans = 1;
a = a % mod;
while (b) {
if (b & 1) ans = ans * a % mod;
a = a * a % mod;
b >>= 1;
}
return ans % mod;
}
ll ask(int l, int r, int add, int mod) {
iter llc = split(l), rrc = split(r + 1);
ll ans = 0;
for (; llc != rrc; llc++) ans = (ans + ll(llc->r - llc->l + 1) * fpow(llc->v, (ll)add, (ll)mod)) % mod;
return ans;
}
ll randd() {
ll ans = seed;
seed = (seed * 7 + 13) % modd;
return ans;
}

int main(int argc, char const *argv[]) {
cin >> n >> m >> seed >> vm;
for (int i = 1; i <= n; i++) {
a[i] = (randd() % vm) + 1;
s.insert(node(i, i, a[i]));
}
s.insert(node(n + 1, n + 1, 0));
while (m--) {
int opt = int(randd() % 4) + 1;
int l = int(randd() % n) + 1;
int r = int(randd() % n) + 1;
if (l > r) swap(l, r);
if (opt == 3) x = int(randd() % (r - l + 1)) + 1;
else x = int(randd() % vm) + 1;
if (opt == 4) y = int(randd() % vm) + 1;
if (opt == 1) add(l, r, ll(x));
else if (opt == 2) assign(l, r, ll(x));
else if (opt == 3) printf("%lld\n", kth(l, r, x));
else printf("%lld\n", ask(l, r, x, y));
}
return 0;
}

左偏树

int merge(int x, int y) {
if (!x or !y) return x + y;
if (val[x] > val[y]) swap(x, y);
ch[x][1] = merge(ch[x][1], y);
fa[ch[x][1]] = x;
if (dis[ch[x][0]] < dis[ch[x][1]]) swap(ch[x][0], ch[x][1]);
dis[x] = dis[ch[x][1]] + 1;
return x;
}

FHQ Treap

void update(int x) {siz[x] = 1 + siz[tree[x][0]] + siz[tree[x][1]];}
int randoom() {return rand() << 15 | rand();}
int newnode(int x) {
siz[++cnt] = 1; val[cnt] = x;
cv[cnt] = randoom(); return cnt;
}
void split(int now, int k, int &x, int &y) {
if (!now) {x = y = 0; return;}
if (val[now] <= k) x = now, split(tree[now][1], k, tree[now][1], y);
else y = now, split(tree[now][0], k, x, tree[now][0]);
update(now);
}
int merge(int x, int y) {
if (!x or !y) return x + y;
if (cv[x] < cv[y]) {
tree[x][1] = merge(tree[x][1], y);
update(x); return x;
}
else {
tree[y][0] = merge(x, tree[y][0]);
update(y); return y;
}
}
int kth(int now, int k) {
if (k <= siz[tree[now][0]]) kth(tree[now][0], k);
else if (k == siz[tree[now][0]] + 1) return now;
else kth(tree[now][1], k - siz[tree[now][0]] - 1);
}

int main(int argc, char const *argv[]) {
srand(time(NULL)); scanf("%d", &n);
for (int i = 1; i <= n; i++) {
scanf("%d%d", &opt, &a);
switch(opt) {
case 1 : split(root, a, x, y); root = merge(merge(x ,newnode(a)), y); break;
case 2 : split(root, a, x, z); split(x, a - 1, x, y); y = merge(tree[y][0], tree[y][1]); root = merge(merge(x, y), z); break;
case 3 : split(root, a - 1, x, y); printf("%d\n", siz[x] + 1); root = merge(x, y); break;
case 4 : printf("%d\n", val[kth(root, a)]); break;
case 5 : split(root, a - 1, x, y); printf("%d\n", val[kth(x, siz[x])]); root = merge(x, y); break;
case 6 : split(root, a, x, y); printf("%d\n", val[kth(y, 1)]); root = merge(x, y); break;
default : break;
}
}
return 0;
}

Splay

const int INF = 0x7fffffff;
namespace Splay {
struct node *null;
struct node {
node *ch[2]; int same, val, siz;
int whetherv(int v) {
if (v == val) return -1;
else return v < val ? 0 : 1;
}
int whetherk(int k) {
if (k <= ch[0]->siz) return 0;
else if (k <= ch[0]->siz + same) return -1;
else return 1;
}
void update() {siz = same + ch[0]->siz + ch[1]->siz;}
node(int x) : same(1), val(x), siz(1) {ch[0] = ch[1] = null;}
} *root;
#define
void init() {
null = new node(0);
root = null->ch[0] = null->ch[1] = null;
null->siz = null->same = 0;
}
void rotate(ND &now, int l) { //l=0左旋
ND x = now->ch[l ^ 1];
now->ch[l ^ 1] = x->ch[l];
x->ch[l] = now; now->update();
x->update(); now = x;
}
void splay(int val, ND &f) {
int dir = f->whetherv(val);
if (dir != -1 and f->ch[dir] != null) {
int dir2 = f->ch[dir]->whetherv(val);
if (dir2 != -1 and f->ch[dir]->ch[dir2] != null) {
splay(val, f->ch[dir]->ch[dir2]);
if (dir == dir2) rotate(f, dir2 ^ 1), rotate(f, dir ^ 1);
else rotate(f->ch[dir], dir2 ^ 1), rotate(f, dir ^ 1);
}
else rotate(f, dir ^ 1);
}
}
void kth(int k, ND &f) {
int dir = f->whetherk(k);
if (dir == 1) k -= f->ch[0]->siz + f->same;
if (dir == -1) return;
int dir2 = f->ch[dir]->whetherk(k);
int k2 = (dir2 == 1) ? k - (f->ch[dir]->ch[0]->siz + f->ch[dir]->same) : k;
if (dir2 != -1) {
kth(k2, f->ch[dir]->ch[dir2]);
if (dir == dir2) rotate(f, dir2 ^ 1), rotate(f, dir ^ 1);
else rotate(f->ch[dir], dir2 ^ 1), rotate(f, dir ^ 1);
}
else rotate(f, dir ^ 1);
}
ND split(int val, ND &f) {
if (f == null) return null;
splay(val, f); node *x, *y;
if (f->val <= val) x = f, y = f->ch[1], f->ch[1] = null;
else x = f->ch[0], y = f, f->ch[0] = null;
f->update(); f = x;
return y;
}
void merge(ND &x, ND &y) {
if (x == null) swap(x, y);
splay(INF, x);
x->ch[1] = y; y = null; x->update();
}
void insert(int val, ND &f = root) {
ND x = split(val, f);
if (f->val == val) f->same++;
else {ND nw = new node(val); merge(f, nw);}
merge(f, x);
}
void dele(int val, ND &f = root) {
ND x = split(val, f);
if (f->val == val and --(f->same) < 1) {
ND y = f->ch[0];
delete f; f = y;
}
merge(f, x);
}
int rank(int k, ND &f = root) {splay(k, f); return f->ch[0]->siz + 1;}
int kthhh(int k, ND &f = root) {kth(k, f); return f->val;}
int pre(int k, ND &f = root) {
splay(k, f);
if (f->val >= k) {
if (f->ch[0] == null) return -INF;
splay(INF, f->ch[0]);
return f->ch[0]->val;
}
else return f->val;
}
int nxt(int k, ND &f = root) {
splay(k, f);
if (f->val <= k) {
if (f->ch[1] == null) return INF;
splay(-INF, f->ch[1]);
return f->ch[1]->val;
}
else return f->val;
}
}
int n, opt, x, y;

int main(int argc, char const *argv[]) {
Splay::init(); cin >> n;
while (n--) {
cin >> opt >> x;
switch (opt) {
case 1 : Splay::insert(x); break;
case 2 : Splay::dele(x); break;
case 3 : cout << Splay::rank(x) << endl; break;
case 4 : cout << Splay::kthhh(x) << endl; break;
case 5 : cout << Splay::pre(x) << endl; break;
case 6 : cout << Splay::nxt(x) << endl; break;
default : break;
}
}
return 0;
}

LCT

namespace LCT {
struct node *null;
struct node {
node *ch[2], *fa; int rev, sum, val;
bool whether() {return fa->ch[1] == this;}
bool isroot() {return fa == null or (fa->ch[0] != this and fa->ch[1] != this);}
void update() {sum = ch[0]->sum ^ ch[1]->sum ^ val;}
void down() {
if (this == null or !rev) return;
swap(ch[0], ch[1]);
ch[0]->rev ^= 1; ch[1]->rev ^= 1;
rev = 0;
}
void setnode(bool k, node *c) {
down(); ch[k] = c;
if (c != null) c->fa = this;
}
}pool[A];
#define
void init() {
null = pool;
null->ch[0] = null->ch[1] = null->fa = null;
null->rev = 0;
}
ND newnode(int val) {
ND x = pool + ++tot;
x->val = val; x->rev = 0;
x->ch[0] = x->ch[1] = x->fa = null;
return x;
}
void rotate(ND x) {
node *fa = x->fa, *grand = fa->fa;
if (!fa->isroot()) grand->down();
fa->down(); x->down();
int dir = x->whether();
fa->setnode(dir, x->ch[dir ^ 1]);
if (fa->isroot()) x->fa = fa->fa;
else grand->setnode(fa->whether(), x);
x->setnode(dir ^ 1, fa);
fa->update(); x->update();
}
void fix(ND x) {if (!x->isroot()) fix(x->fa); x->down();}
void splay(ND x) {
fix(x);
while (!x->isroot()) {
if (!x->fa->isroot()) x->whether() == x->fa->whether() ? rotate(x->fa) : rotate(x);
rotate(x);
}
x->update();
}
ND access(ND x) {
ND y = null;
while (x != null) {
splay(x); x->ch[1] = y;
x->update(); y = x; x = x->fa;
}
return y;
}
void makeroot(ND x) {access(x)->rev = 1; splay(x);}
void link(ND x, ND y) {makeroot(x); x->fa = y;}
void cut(ND x, ND y) {
makeroot(x); access(y); splay(x);
if (x->ch[1] == y and x->ch[1]->ch[0] != null) return;
x->ch[1] = y->fa = null;
}
ND find(ND x) {
access(x); splay(x);
while (x->ch[0] != null) x->down(), x = x->ch[0];
splay(x); return x;
}
void change(ND x, int y) {
access(x); splay(x);
x->val = y; x->update();
}
int query(ND x, ND y) {
makeroot(x); access(y);
splay(y); return y->sum;
}
}
inline char GETCHAR() {
static char buf[B], *p1 = buf, *p2 = buf;
return p1 == p2 and (p2 = (p1 = buf) + fread(buf, 1, B, stdin), p1 == p2) ? EOF : *p1++;
}
template<class T> void read(T &x) {
x = 0; int flag = 0; char ch = GETCHAR();
while (!isdigit(ch)) flag |= ch == '-', ch = GETCHAR();
while (isdigit(ch)) x = x * 10 + (ch ^ 48), ch = GETCHAR();
x = flag ? -x : x;
}

int main(int argc, char const *argv[]) {
LCT::init(); read(n); read(m);
for (int i = 1; i <= n; i++) read(x), LCT::newnode(x);
while (m--) {
read(opt); read(x); read(y);
LCT::ND a = (LCT::pool + x);
LCT::ND b = (opt == 3) ? LCT::null : (LCT::pool + y);
switch(opt) {
case 0 : printf("%d\n", LCT::query(a, b)); break;
case 1 : if (LCT::find(a) != LCT::find(b)) LCT::link(a, b); break;
case 2 : if (LCT::find(a) == LCT::find(b)) LCT::cut(a, b); break;
case 3 : LCT::change(a, y); break;
}
}
}

树套树

二逼平衡树,Templates_中国剩余定理_28套线段树

int w[A], ch[A][2], val[A], cv[A], siz[A], cnt;
int n, m, a, b, c, opt;
namespace Fhq {
void update(int x) {siz[x] = siz[ch[x][0]] + siz[ch[x][1]] + 1;}
int newnode(int x) {
siz[++cnt] = 1; val[cnt] = x;
cv[cnt] = rand(); return cnt;
}
void split(int now, int k, int &x, int &y) {
if (!now) {x = y = 0; return;}
if (val[now] <= k) x = now, split(ch[now][1], k, ch[x][1], y);
else y = now, split(ch[now][0], k, x, ch[y][0]);
update(now);
}
int merge(int x, int y) {
if (!x or !y) return x + y;
if (cv[x] < cv[y]) {ch[x][1] = merge(ch[x][1], y); update(x); return x;}
else {ch[y][0] = merge(x, ch[y][0]); update(y); return y;}
}
int find(int &root, int k) {
int x, y; split(root, k - 1, x, y);
int tmp = siz[x]; root = merge(x, y);
return tmp;
}
int kth(int now, int k) {
if (siz[now] < k or !siz[now] or !k) return 0x7fffffff;
if (siz[ch[now][0]] + 1 == k) return val[now];
if (siz[ch[now][0]] >= k) return kth(ch[now][0], k);
else return kth(ch[now][1], k - siz[ch[now][0]] - 1);
}
void insert(int &root, int k) {
int x, y; split(root, k, x, y);
root = merge(merge(x, newnode(k)), y);
}
void dele(int &root, int k) {
int x, y, z;
split(root, k, x, z); split(x, k - 1, x, y);
y = merge(ch[y][0], ch[y][1]);
root = merge(merge(x, y), z);
}
int pre(int &root, int k) {
int x, y, z; split(root, k - 1, x, y);
z = kth(x, siz[x]); root = merge(x, y);
return z == 0x7fffffff ? -0x7fffffff : z;
}
int nxt(int &root, int k) {
int x, y, z; split(root, k, x, y);
z = kth(y, 1); root = merge(x, y);
return z;
}
}
namespace SegmentTree {
struct node {int l, r, root;}tree[A];
void build(int k, int l, int r) {
tree[k].l = l; tree[k].r = r;
for (int i = l; i <= r; i++) Fhq::insert(tree[k].root, w[i]);
if (l == r) return;
int m = (l + r) >> 1;
build(k << 1, l, m); build(k << 1 | 1, m + 1, r);
}
void change(int k) {
Fhq::dele(tree[k].root, w[a]); Fhq::insert(tree[k].root, b);
if (tree[k].l == tree[k].r) return;
int m = (tree[k].l + tree[k].r) >> 1;
if (a <= m) change(k << 1);
else change(k << 1 | 1);
}
int ask(int k) {
if (tree[k].l >= a and tree[k].r <= b) return Fhq::find(tree[k].root, c);
int m = (tree[k].l + tree[k].r) >> 1, ans = 0;
if (a <= m) ans += ask(k << 1);
if (b > m) ans += ask(k << 1 | 1);
return ans;
}
int pre(int k) {
if (tree[k].l >= a and tree[k].r <= b) return Fhq::pre(tree[k].root, c);
int m = (tree[k].l + tree[k].r) >> 1, ans = -0x7fffffff;
if (a <= m) ans = max(ans, pre(k << 1));
if (b > m) ans = max(ans, pre(k << 1 | 1));
return ans;
}
int nxt(int k) {
if (tree[k].l >= a and tree[k].r <= b) return Fhq::nxt(tree[k].root, c);
int m = (tree[k].l + tree[k].r) >> 1, ans = 0x7fffffff;
if (a <= m) ans = min(ans, nxt(k << 1));
if (b > m) ans = min(ans, nxt(k << 1 | 1));
return ans;
}
}
namespace operation {
void operation1() {
scanf("%d%d%d", &a, &b, &c);
printf("%d\n", SegmentTree::ask(1) + 1);
}
void operation2() {
int cc; scanf("%d%d%d", &a, &b, &cc);
int l = 0, r = 1e8, ans = 0;
while (l <= r) {
int m = (l + r) >> 1; c = m;
if (SegmentTree::ask(1) + 1 <= cc) ans = m, l = m + 1;
else r = m - 1;
}
printf("%d\n", ans);
}
void operation3() {
scanf("%d%d", &a, &b);
SegmentTree::change(1);
w[a] = b;
}
void operation4() {
scanf("%d%d%d", &a, &b, &c);
printf("%d\n", SegmentTree::pre(1));
}
void operation5() {
scanf("%d%d%d", &a, &b, &c);
printf("%d\n", SegmentTree::nxt(1));
}
}

计 算 几 何 计算几何 计算几何

计算几何知识几乎为空。

求任意多边形面积

double area() {
double s = 0;
for (int i = 1; i <= top; i++) e[i].x = x[sta[i]], e[i].y = y[sta[i]];
for (int i = 1; i < top; i++) s += e[i].x * e[i + 1].y;
s += e[top].x * e[1].y;
for (int i = 2; i <= top; i++) s -= e[i].x * e[i - 1].y;
s -= e[1].x * e[top].y; s /= 2;
return fabs(s);
}

其 他 其他 其他

快速读入/快速输出

用了标准库里面的Templates_CSP_29Templates_NOIP_30数组不要开太大不然输不进去
重定义Templates_中国剩余定理_31之后要用Templates_NOIP_32就全用,不然也是会出错
输出long long

char Getchar() {
static char buf[100010], *p1 = buf, *p2 = buf;
return p1 == p2 and (p2 = (p1 = buf) + fread(buf, 1, 100010, stdin), p1 == p2) ? EOF : *p1++;
}
template<class T> void read(T &x) {
bool flag = 0; x = 0; char ch = Getchar();
while (!isdigit(ch)) flag |= ch == '-', ch = Getchar();
while (isdigit(ch)) x = x * 10 + ch - '0', ch = Getchar();
x = flag ? -x : x;
}
template<class T> void write(T x) {
if (x < 0) x = -x, putchar('-');
if (x > 9) write(x / 10);
putchar(x % 10 + '0');
}

生成数据

srand(1293123); char s[105];
for (int i = 1; i <= 10; i++) {
sprintf(s, "test%d.in", i);
freopen(s, "w", stdout);
for (int j = 1; j <= 10; j++) cout << rand() % 10 + 1 << " "; puts("");
fclose(stdout);
}

归并排序(逆序对)

void merge(int a[], int l, int r) { //a就是需要排序/求逆序对的数组
if (l == r) return;
int m = (l + r) >> 1, i = l, j = m + 1, o = l;
merge(a, l, m); //先处理子问题
merge(a, m + 1, r);
while (i <= m && j <= r) //将小区间有序合并
if (a[i] > a[j]) tmp[o++] = a[j++], ans += m - i + 1; //ans统计逆序对,好好理解
//i后面到m的元素一定比a[j]大
else tmp[o++] = a[i++];
while (i <= m) tmp[o++] = a[i++];
while (j <= r) tmp[o++] = a[j++];
for (int i = l; i <= r; ++i) a[i] = tmp[i];
}

对拍

color A
echo off
:loop
echo 已运行%a%
set /a a+=1
rand.exe
my.exe
std.exe
fc my.out std.out
if not errorlevel 1 goto

删除程序注释

void dfa() {
freopen("1.in", "r", stdin);
int c, state = 0;
while ((c = getchar()) != EOF) {
if (state == 0 and c == '/') state = 1; // ex. [/]
else if (state == 1 and c == '*') state = 2; // ex. [/*]
else if (state == 1 and c == '/') state = 4; // ex. [//]
else if (state == 1) putchar('/'), state = 0; // ex. [<secure/_stdio.h> or 5/3]
else if (state == 2 and c == '*') state = 3; // ex. [/*he*]
else if (state == 2) state = 2; // ex. [/*heh]
else if (state == 3 and c == '/') state = 0; // ex. [/*heh*/]
else if (state == 3) state = 2; // ex. [/*heh*e]
else if (state == 4 and c == '\\') state = 9; // ex. [//hehe\]
else if (state == 9 and c == '\\') state = 9; // ex. [//hehe\\\\\]
else if (state == 9) state = 4; // ex. [//hehe\<enter> or //hehe\a]
else if (state == 4 and c == '\n') state = 0; // ex. [//hehe<enter>]
else if (state == 0 and c == '\'') state = 5; // ex. [']
else if (state == 5 and c == '\\') state = 6; // ex. ['\]
else if (state == 6) state = 5; // ex. ['\n or '\' or '\t etc.]
else if (state == 5 and c == '\'') state = 0; // ex. ['\n' or '\'' or '\t' ect.]
else if (state == 0 and c == '\"') state = 7; // ex. ["]
else if (state == 7 and c == '\\') state = 8; // ex. ["\]
else if (state == 8) state = 7; // ex. ["\n or "\" or "\t ect.]
else if (state == 7 and c == '\"') state = 0; // ex. ["\n" or "\"" or "\t" ect.]
if ((state == 0 and c != '/') || state == 5 || state == 6 || state == 7 || state == 8) putchar(c);
}
}

任意形式转化为string

void to_string(string &result, const T &t) {
ostringstream oss; //创建一个流
oss << t; //把值传递入流中
result = oss.str(); //获取转换后的字符并将其写入result
}

莫队

void MO(int x) {
int L = Ask[x].l, R = Ask[x].r;
while (l > L) Ins(--l);
while (l < L) Del(l++);
while (r > R) Del(r--);
while (r < R) Ins(++r);
Ask[x].ans = now;
}

最大子矩阵

for (int i = 1; i <= n; i++) {
memset(f, 0, sizeof f); memset(p, 0, sizeof p);
for (int j = i + 1; j <= n; j++) {
for (int k = 1; k <= n; k++) f[k] += a[j][k];
for (int l = 1; l <= n; l++) p[l] = max(p[l - 1] + f[l], f[l]);
int maxx = 0;
for (int o = 1; o <= n; o++) maxx = max(maxx, p[o]);
ans = max(ans, maxx);
}
}

打开文件

FILE *pFile;
char buffer[100];
pFile = fopen("myfile.txt", "r");
if (pFile == NULL) perror("Error opening file");
else {
while (!feof(pFile)) {
if (fgets(buffer, 100, pFile) == NULL) break;
fputs(buffer, stdout);
}
fclose(pFile);
}

放到最后的高精度1

namespace BigInteger {
#define
using std::sprintf;
using std::string;
using std::max;
using std::istream;
using std::ostream;
struct Big_integer {
int d[maxn], len;
void clean() {while(len > 1 and !d[len - 1]) len--;}
Big_integer() {memset(d, 0, sizeof d); len = 1;}
Big_integer(int num) {*this = num;}
Big_integer(char* num) {*this = num;}
Big_integer operator = (const char *num) {
memset(d, 0, sizeof d);
len = strlen(num);
for (int i = 0; i < len; i++) d[i] = num[len - 1 - i] - '0';
clean();
return *this;
}
Big_integer operator = (int num) {
char s[10005];
sprintf(s, "%d", num);
*this = s;
return *this;
}
Big_integer operator + (const Big_integer &b) {
Big_integer c = *this; int i;
for (i = 0; i < b.len; i++) {
c.d[i] += b.d[i];
if (c.d[i] > 9) c.d[i] %= 10, c.d[i + 1]++;
}
while (c.d[i] > 9) c.d[i++] %= 10, c.d[i]++;
c.len = max(len, b.len);
if (c.d[i] and c.len <= i) c.len = i + 1;
return c;
}
Big_integer operator - (const Big_integer &b) {
Big_integer c = *this; int i;
for (i = 0; i < b.len; i++) {
c.d[i] -= b.d[i];
if (c.d[i] < 0) c.d[i] += 10, c.d[i + 1]--;
}
while (c.d[i] < 0) c.d[i++] += 10, c.d[i]--;
c.clean();
return c;
}
Big_integer operator * (const Big_integer &b) const {
int i, j; Big_integer c;
c.len = len + b.len;
for (j = 0; j < b.len; j++)
for (i = 0; i < len; i++)
c.d[i + j] += d[i] * b.d[j];
for (i = 0; i < c.len - 1; i++) {
c.d[i + 1] += c.d[i] / 10;
c.d[i] %= 10;
}
c.clean();
return c;
}
Big_integer operator / (const Big_integer &b) {
int i, j;
Big_integer c = *this, a = 0;
for (i = len - 1; i >= 0; i--) {
a = a * 10 + d[i];
for (j = 0; j < 10; j++) if (a < b * (j + 1)) break;
c.d[i] = j;
a = a - b * j;
}
c.clean();
return c;
}
Big_integer operator % (const Big_integer &b) {
int i, j; Big_integer a = 0;
for (i = len - 1; i >= 0; i--) {
a = a * 10 + d[i];
for (j = 0; j < 10; j++) if (a < b * (j + 1)) break;
a = a - b * j;
}
return a;
}
Big_integer operator += (const Big_integer &b) {
*this = *this + b;
return *this;
}
bool operator < (const Big_integer &b) const {
if (len != b.len) return len < b.len;
for (int i = len - 1; i >= 0; i--)
if (d[i] != b.d[i])
return d[i] < b.d[i];
return false;
}
bool operator > (const Big_integer &b) const {return b < *this;}
bool operator <= (const Big_integer &b) const {return !(b < *this);}
bool operator >= (const Big_integer &b) const {return !(b > *this);}
bool operator != (const Big_integer &b) const {return b < *this or b > *this;}
bool operator == (const Big_integer &b) const {return !(b < *this) and !(b > *this);}
string str() const {
char s[maxn];
for (int i = 0; i < len; i++) s[len - 1 - i] = d[i] + '0';
return s;
}
};
istream& operator >> (istream &in, Big_integer &x) {
string s;
in >> s;
x = s.c_str();
return in;
}
ostream& operator << (ostream &out, const Big_integer &x) {
out << x.str();
return out;
}
}
using namespace BigInteger;

放到最后的高精度2

#define
#define
#define
typedef int bignum_t[MAXX + 1];
int read(bignum_t a, istream&is = cin) {
char buf[MAXX * DIGIT + 1], ch;
int i, j;
memset((void*)a, 0, sizeof(bignum_t));
if (!(is >> buf)) return 0;
for (a[0] = strlen(buf), i = a[0] / 2 - 1; i >= 0; i--)
ch = buf[i], buf[i] = buf[a[0] - 1 - i], buf[a[0] - 1 - i] = ch ;
for (a[0] = (a[0] + DIGIT - 1) / DIGIT, j = strlen(buf); j < a[0]*DIGIT; buf[j++] = '0');
for (i = 1; i <= a[0]; i++)
for (a[i] = 0, j = 0; j < DIGIT; j++)
a[i] = a[i] * 10 + buf[i * DIGIT - 1 - j] - '0';
for (; !a[a[0]] and a[0] > 1; a[0]--);
return 1;
}
void write(const bignum_t a, ostream&os = cout) {
int i, j;
for (os << a[i = a[0]], i--; i; i--)
for (j = DEPTH / 10; j; j /= 10)
os << a[i] / j % 10;
}
int comp(const bignum_t a, const bignum_t b) {
if (a[0] != b[0]) return a[0] - b[0];
for (int i = a[0]; i; i--) if (a[i] != b[i]) return a[i] - b[i];
return 0;
}
int comp(const bignum_t a, const int b) {
int c[12] = {1};
for (c[1] = b; c[c[0]] >= DEPTH; c[c[0] + 1] = c[c[0]] / DEPTH, c[c[0]] %= DEPTH, c[0]++);
return comp(a, c);
}
int comp(const bignum_t a, const int c, const int d, const bignum_t b) {
int i, t = 0, O = -DEPTH * 2;
if (b[0] - a[0] < d and c) return 1;
for (i = b[0]; i > d; i--) {
t = t * DEPTH + a[i - d] * c - b[i];
if (t > 0) return 1;
if (t < O) return 0;
}
for (i = d; i; i--) {
t = t * DEPTH - b[i];
if (t > 0) return 1;
if (t < O) return 0;
}
return t > 0;
}
void add(bignum_t a, const bignum_t b) {
int i;
for (i = 1; i <= b[0]; i++)
if ((a[i] += b[i]) >= DEPTH)
a[i] -= DEPTH, a[i + 1]++;
if (b[0] >= a[0]) a[0] = b[0];
else for (; a[i] >= DEPTH and i < a[0]; a[i] -= DEPTH, i++, a[i]++);
a[0] += (a[a[0] + 1] > 0);
}
void add(bignum_t a, const int b) {
int i = 1;
for (a[1] += b; a[i] >= DEPTH and i < a[0]; a[i + 1] += a[i] / DEPTH, a[i] %= DEPTH, i++);
for (; a[a[0]] >= DEPTH; a[a[0] + 1] = a[a[0]] / DEPTH, a[a[0]] %= DEPTH, a[0]++);
}
void sub(bignum_t a, const bignum_t b) {
int i;
for (i = 1; i <= b[0]; i++) if ((a[i] -= b[i]) < 0) a[i + 1]--, a[i] += DEPTH;
for (; a[i] < 0; a[i] += DEPTH, i++, a[i]--);
for (; !a[a[0]] and a[0] > 1; a[0]--);
}
void sub(bignum_t a, const int b) {
int i = 1;
for (a[1] -= b; a[i] < 0; a[i + 1] += (a[i] - DEPTH + 1) / DEPTH, a[i] -= (a[i] - DEPTH + 1) / DEPTH * DEPTH, i++);
for (; !a[a[0]] and a[0] > 1; a[0]--);
}
void sub(bignum_t a, const bignum_t b, const int c, const int d) {
int i, O = b[0] + d;
for (i = 1 + d; i <= O; i++)
if ((a[i] -= b[i - d] * c) < 0)
a[i + 1] += (a[i] - DEPTH + 1) / DEPTH, a[i] -= (a[i] - DEPTH + 1) / DEPTH * DEPTH;
for (; a[i] < 0; a[i + 1] += (a[i] - DEPTH + 1) / DEPTH, a[i] -= (a[i] - DEPTH + 1) / DEPTH * DEPTH, i++);
for (; !a[a[0]] and a[0] > 1; a[0]--);
}
void mul(bignum_t c, const bignum_t a, const bignum_t b) {
int i, j;
memset((void*)c, 0, sizeof(bignum_t));
for (c[0] = a[0] + b[0] - 1, i = 1; i <= a[0]; i++)
for (j = 1; j <= b[0]; j++)
if ((c[i + j - 1] += a[i] * b[j]) >= DEPTH)
c[i + j] += c[i + j - 1] / DEPTH, c[i + j - 1] %= DEPTH;
for (c[0] += (c[c[0] + 1] > 0); !c[c[0]] and c[0] > 1; c[0]--);
}
void mul(bignum_t a, const int b) {
int i;
for (a[1] *= b, i = 2; i <= a[0]; i++) {
a[i] *= b;
if (a[i - 1] >= DEPTH) a[i] += a[i - 1] / DEPTH, a[i - 1] %= DEPTH;
}
for (; a[a[0]] >= DEPTH; a[a[0] + 1] = a[a[0]] / DEPTH, a[a[0]] %= DEPTH, a[0]++);
for (; !a[a[0]] and a[0] > 1; a[0]--);
}
void mul(bignum_t b, const bignum_t a, const int c, const int d) {
int i;
memset((void*)b, 0, sizeof(bignum_t));
for (b[0] = a[0] + d, i = d + 1; i <= b[0]; i++)
if ((b[i] += a[i - d] * c) >= DEPTH)
b[i + 1] += b[i] / DEPTH, b[i] %= DEPTH ;
for (; b[b[0] + 1]; b[0]++, b[b[0] + 1] = b[b[0]] / DEPTH, b[b[0]] %= DEPTH);
for (; !b[b[0]] and b[0] > 1; b[0]--);
}
void div(bignum_t c, bignum_t a, const bignum_t b) {
int h, l, m, i;
memset((void*)c, 0, sizeof(bignum_t));
c[0] = (b[0] < a[0] + 1) ? (a[0] - b[0] + 2) : 1;
for (i = c[0]; i; sub(a, b, c[i] = m, i - 1), i--)
for (h = DEPTH - 1, l = 0, m = (h + l + 1) >> 1; h > l; m = (h + l + 1) >> 1)
if (comp(b, m, i - 1, a)) h = m - 1;
else l = m;
for (; !c[c[0]] and c[0] > 1; c[0]--);
c[0] = c[0] > 1 ? c[0] : 1;
}
void div(bignum_t a, const int b, int&c) {
int i;
for (c = 0, i = a[0]; i; c = c * DEPTH + a[i], a[i] = c / b, c %= b, i--);
for (; !a[a[0]] and a[0] > 1; a[0]--);
}
void sqrt(bignum_t b, bignum_t a) {
int h, l, m, i;
memset((void*)b, 0, sizeof(bignum_t));
for (i = b[0] = (a[0] + 1) >> 1; i; sub(a, b, m, i - 1), b[i] += m, i--)
for (h = DEPTH - 1, l = 0, b[i] = m = (h + l + 1) >> 1; h > l; b[i] = m = (h + l + 1) >> 1)
if (comp(b, m, i - 1, a)) h = m - 1;
else l = m;
for (; !b[b[0]] and b[0] > 1; b[0]--);
for (i = 1; i <= b[0]; b[i++] >>= 1);
}
int length(const bignum_t a) {
int t, ret;
for (ret = (a[0] - 1) * DIGIT, t = a[a[0]]; t; t /= 10, ret++);
return ret > 0 ? ret : 1;
}
int digit(const bignum_t a, const int b) {
int i, ret;
for (ret = a[(b - 1) / DIGIT + 1], i = (b - 1) % DIGIT; i; ret /= 10, i--);
return ret % 10;
}
int zeronum(const bignum_t a) {
int ret, t;
for (ret = 0; !a[ret + 1]; ret++);
for (t = a[ret + 1], ret *= DIGIT; !(t % 10); t /= 10, ret++);
return ret;
}
void comp(int *a, const int l, const int h, const int d) {
int i, j, t;
for (i = l; i <= h; i++)
for (t = i, j = 2; t > 1; j++)
while (!(t % j))
a[j] += d, t /= j;
}
void convert(int*a, const int h, bignum_t b) {
int i, j, t = 1;
memset(b, 0, sizeof(bignum_t));
for (b[0] = b[1] = 1, i = 2; i <= h; i++)
if (a[i])
for (j = a[i]; j; t *= i, j--)
if (t * i > DEPTH)
mul(b, t), t = 1;
mul(b, t);
}
void combination(bignum_t a, int m, int n) {
int *t = new int[m + 1];
memset((void*)t, 0, sizeof(int) * (m + 1));
comp(t, n + 1, m, 1);
comp(t, 2, m - n, -1);
convert(t, m, a);
delete[] t;
}
void permutation(bignum_t a, int m, int n) {
int i, t = 1;
memset(a, 0, sizeof(bignum_t));
a[0] = a[1] = 1;
for (i = m - n + 1; i <= m; t *= i++)
if (t * i > DEPTH)
mul(a, t), t = 1;
mul(a, t);
}
#define
#define
int read(bignum_t a, int &sgn, istream &is = cin) {
char str[MAXX * DIGIT + 2], ch, *buf; int i, j;
memset((void*)a, 0, sizeof(bignum_t));
if (!(is >> str)) return 0;
buf = str, sgn = 1;
if (*buf == '-') sgn = -1, buf++;
for (a[0] = strlen(buf), i = a[0] / 2 - 1; i >= 0; i--)
ch = buf[i], buf[i] = buf[a[0] - 1 - i], buf[a[0] - 1 - i] = ch ;
for (a[0] = (a[0] + DIGIT - 1) / DIGIT, j = strlen(buf); j < a[0]*DIGIT; buf[j++] = '0');
for (i = 1; i <= a[0]; i++)
for (a[i] = 0, j = 0; j < DIGIT; j++)
a[i] = a[i] * 10 + buf[i * DIGIT - 1 - j] - '0';
for (; !a[a[0]] and a[0] > 1; a[0]--);
if (a[0] == 1 and !a[1]) sgn = 0;
return 1;
}
struct bignum {
bignum_t num; int sgn;
public:
inline bignum() {
memset(num, 0, sizeof(bignum_t));
num[0] = 1; sgn = 0;
}
inline int operator!() {return num[0] == 1 and !num[1];}
inline bignum &operator = (const bignum &a) {
memcpy(num, a.num, sizeof(bignum_t));
sgn = a.sgn;
return *this;
}
inline bignum &operator = (const int a) {
memset(num, 0, sizeof(bignum_t));
num[0] = 1; sgn = SGN(a); add(num, sgn * a);
return *this;
};
inline bignum &operator += (const bignum &a) {
if (sgn == a.sgn) add(num, a.num);
else if (sgn and a.sgn) {
int ret = comp(num, a.num);
if (ret > 0) sub(num, a.num);
else if (ret < 0) {
bignum_t t;
memcpy(t, num, sizeof(bignum_t));
memcpy(num, a.num, sizeof(bignum_t));
sub(num, t); sgn = a.sgn;
}
else memset(num, 0, sizeof(bignum_t)), num[0] = 1, sgn = 0;
}
else if (!sgn) memcpy(num, a.num, sizeof(bignum_t)), sgn = a.sgn;
return *this;
}
inline bignum &operator += (const int a) {
if (sgn * a > 0) add(num, ABS(a));
else if (sgn and a) {
int ret = comp(num, ABS(a));
if (ret > 0) sub(num, ABS(a));
else if (ret < 0) {
bignum_t t;
memcpy(t, num, sizeof(bignum_t));
memset(num, 0, sizeof(bignum_t));
num[0] = 1;
add(num, ABS(a));
sgn = -sgn;
sub(num, t);
}
else memset(num, 0, sizeof(bignum_t)), num[0] = 1, sgn = 0;
}
else if (!sgn) sgn = SGN(a), add(num, ABS(a));
return *this;
}
inline bignum operator + (const bignum &a) {
bignum ret;
memcpy(ret.num, num, sizeof (bignum_t));
ret.sgn = sgn;
ret += a;
return ret;
}
inline bignum operator + (const int a) {
bignum ret;
memcpy(ret.num, num, sizeof (bignum_t));
ret.sgn = sgn;
ret += a;
return ret;
}
inline bignum &operator -= (const bignum &a) {
if (sgn * a.sgn < 0) add(num, a.num);
else if (sgn and a.sgn) {
int ret = comp(num, a.num);
if (ret > 0)sub(num, a.num);
else if (ret < 0) {
bignum_t t;
memcpy(t, num, sizeof(bignum_t));
memcpy(num, a.num, sizeof(bignum_t));
sub(num, t);
sgn = -sgn;
}
else memset(num, 0, sizeof(bignum_t)), num[0] = 1, sgn = 0 ;
}
else if (!sgn) add(num, a.num), sgn = -a.sgn;
return *this;
}
inline bignum &operator -= (const int a) {
if (sgn * a < 0) add(num, ABS(a));
else if (sgn and a) {
int ret = comp(num, ABS(a));
if (ret > 0) sub(num, ABS(a));
else if (ret < 0) {
bignum_t t;
memcpy(t, num, sizeof(bignum_t));
memset(num, 0, sizeof(bignum_t));
num[0] = 1;
add(num, ABS(a));
sub(num, t);
sgn = -sgn;
}
else memset(num, 0, sizeof(bignum_t)), num[0] = 1, sgn = 0;
}
else if (!sgn) sgn = -SGN(a), add(num, ABS(a));
return *this;
}
inline bignum operator - (const bignum &a) {
bignum ret;
memcpy(ret.num, num, sizeof(bignum_t));
ret.sgn = sgn;
ret -= a;
return ret;
}
inline bignum operator - (const int a) {
bignum ret;
memcpy(ret.num, num, sizeof(bignum_t));
ret.sgn = sgn;
ret -= a;
return ret;
}
inline bignum &operator *= (const bignum &a) {
bignum_t t;
mul(t, num, a.num);
memcpy(num, t, sizeof(bignum_t));
sgn *= a.sgn;
return *this;
}
inline bignum &operator *= (const int a) {
mul(num, ABS(a));
sgn *= SGN(a);
return *this;
}
inline bignum operator * (const bignum &a) {
bignum ret;
mul(ret.num, num, a.num);
ret.sgn = sgn * a.sgn;
return ret;
}
inline bignum operator * (const int a) {
bignum ret;
memcpy(ret.num, num, sizeof (bignum_t));
mul(ret.num, ABS(a));
ret.sgn = sgn * SGN(a);
return ret;
}
inline bignum &operator /= (const bignum &a) {
bignum_t t; div(t, num, a.num);
memcpy (num, t, sizeof(bignum_t));
sgn = (num[0] == 1 and !num[1]) ? 0 : sgn * a.sgn;
return *this;
}
inline bignum &operator /= (const int a) {
int t; div(num, ABS(a), t);
sgn = (num[0] == 1 and !num [1]) ? 0 : sgn * SGN(a);
return *this;
}
inline bignum operator / (const bignum &a) {
bignum ret; bignum_t t;
memcpy(t, num, sizeof(bignum_t));
div(ret.num, t, a.num);
ret.sgn = (ret.num[0] == 1 and !ret.num[1]) ? 0 : sgn * a.sgn ;
return ret;
}
inline bignum operator / (const int a) {
bignum ret; int t;
memcpy(ret.num, num, sizeof(bignum_t));
div(ret.num, ABS(a), t);
ret.sgn = (ret.num[0] == 1 and !ret.num[1]) ? 0 : sgn * SGN(a);
return ret;
}
inline bignum &operator %= (const bignum &a) {
bignum_t t;
div(t, num, a.num);
if (num[0] == 1 and !num[1])sgn = 0;
return *this;
}
inline int operator %= (const int a) {
int t;
div(num, ABS(a), t);
memset(num, 0, sizeof (bignum_t));
num[0] = 1;
add(num, t);
return t;
}
inline bignum operator % (const bignum &a) {
bignum ret; bignum_t t;
memcpy(ret.num, num, sizeof(bignum_t));
div(t, ret.num, a.num);
ret.sgn = (ret.num[0] == 1 and !ret.num [1]) ? 0 : sgn;
return ret;
}
inline int operator % (const int a) {
bignum ret; int t;
memcpy(ret.num, num, sizeof(bignum_t));
div(ret.num, ABS(a), t);
memset(ret.num, 0, sizeof(bignum_t));
ret.num[0] = 1;
add(ret.num, t);
return t;
}
inline bignum &operator ++ () {*this += 1; return *this;}
inline bignum &operator -- () {*this -= 1; return *this;};
inline int operator > (const bignum &a) {return sgn > 0 ? (a.sgn > 0 ? comp(num, a.num) > 0 : 1) : (sgn < 0 ? (a.sgn < 0 ? comp(num, a.num) < 0 : 0) : a.sgn < 0);}
inline int operator > (const int a) {return sgn > 0 ? (a > 0 ? comp(num, a) > 0 : 1) : (sgn < 0 ? (a < 0 ? comp(num, -a) < 0 : 0) : a < 0);}
inline int operator >= (const bignum &a) {return sgn > 0 ? (a.sgn > 0 ? comp(num, a.num) >= 0 : 1) : (sgn < 0 ? (a.sgn < 0 ? comp(num, a.num) <= 0 : 0) : a.sgn <= 0);}
inline int operator >= (const int a) {return sgn > 0 ? (a > 0 ? comp(num, a) >= 0 : 1) : (sgn < 0 ? (a < 0 ? comp(num, -a) <= 0 : 0) : a <= 0);}
inline int operator < (const bignum &a) {return sgn < 0 ? (a.sgn < 0 ? comp(num, a.num) > 0 : 1) : (sgn > 0 ? (a.sgn > 0 ? comp(num, a.num) < 0 : 0) : a.sgn > 0);}
inline int operator < (const int a) {return sgn < 0 ? (a < 0 ? comp(num, -a) > 0 : 1) : (sgn > 0 ? (a > 0 ? comp(num, a) < 0 : 0) : a > 0);}
inline int operator <= (const bignum &a) {return sgn < 0 ? (a.sgn < 0 ? comp(num, a.num) >= 0 : 1) : (sgn > 0 ? (a.sgn > 0 ? comp(num, a.num) <= 0 : 0) : a.sgn >= 0);}
inline int operator <= (const int a) {return sgn < 0 ? (a < 0 ? comp(num, -a) >= 0 : 1) :(sgn > 0 ? (a > 0 ? comp(num, a) <= 0 : 0) : a >= 0);}
inline int operator == (const bignum &a) {return (sgn == a.sgn) ? !comp(num, a.num) : 0;}
inline int operator == (const int a) {return (sgn * a >= 0) ? !comp(num, ABS(a)) : 0;}
inline int operator != (const bignum &a) {return (sgn == a.sgn) ? comp(num, a.num) : 1;}
inline int operator != (const int a) {return (sgn * a >= 0) ? comp(num, ABS(a)) : 1;}
inline int operator [] (const int a) {return digit(num, a);}
friend inline istream &operator >> (istream &is, bignum &a) {
read(a.num, a.sgn, is);
return is;
}
friend inline ostream &operator << (ostream &os, const bignum &a) {
if (a.sgn < 0) os << '-';
write(a.num, os);
return os;
}
friend inline bignum sqrt(const bignum &a) {
bignum ret; bignum_t t;
memcpy(t, a.num, sizeof(bignum_t));
sqrt(ret.num, t);
ret.sgn = ret.num[0] != 1 or ret.num[1];
return ret;
}
friend inline bignum sqrt(const bignum &a, bignum &b) {
bignum ret;
memcpy(b.num, a.num, sizeof(bignum_t));
sqrt(ret.num, b.num);
ret.sgn = ret.num[0] != 1 or ret.num[1];
b.sgn = b.num[0] != 1 or ret.num[1];
return ret;
}
inline int length() {return::length(num);}
inline int zeronum() {return::zeronum(num);}
inline bignum C(const int m, const int n) {combination(num, m, n); sgn = 1; return *this;}
inline bignum P(const int m, const int n) {permutation(num, m, n); sgn = 1; return *this;}
};