2013-team5/常用模板

从 Trac 迁移的文章

这是从旧校内 Wiki 迁移的文章,可能存在一些样式问题,您可以向 memset0 反馈。

原文章内容如下:

{{{
关键词: 后缀数组  AC自动机   AC+dp    分数规划    二分图最小权    二分图最大权  2-sat    最大流     最短路径(负环判定)    

最小生成树(kruskal、并查集)    最小生成树prim    stl优先队列的简单用法   二分图最大匹配     康托展开  最小费用(最大)流    日期

Treap Splay 辛普森  因子分解




后缀数组
const int N = 40005;
int sa[N], rk[N], height[N];

int wa[N], wb[N], wv[N], wts[N];
inline bool cmp(int *r, int a, int b, int len) {
    return (r[a]==r[b]) && (r[a+len]==r[b+len]);
}

void sortSA(char *r, int *sa, int n, int m){
    int i, j, p, *x = wa, *y = wb, *t;
    for(i = 0; i < m; i++)
        wts[i] = 0;
    for(i = 0; i < n; i++)
        wts[x[i]=r[i]]++;
    for(i = 1; i < m; i++)
        wts[i] += wts[i-1];
    for(i = n-1; i >= 0; i--)
        sa[--wts[x[i]]] = i;

    for(j = p = 1; p < n; j <<= 1, m = p){
        for(p=0, i=n-j; i < n; i++)
            y[p++] = i;
        for(i = 0; i < n; i++){
            if(sa[i] >= j)
                y[p++] = sa[i] - j;
        }
        for(i = 0; i < m; i++)
            wts[i] = 0;
        for(i = 0; i < n; i++)
            wts[wv[i]=x[y[i]]]++;
        for(i = 1; i < m; i++)
            wts[i] += wts[i-1];
        for(i = n-1; i >= 0; i--)
            sa[--wts[wv[i]]] = y[i];
        for(t=x,x=y,y=t,x[sa[0]]=0,p=i=1; i < n; i++)
            x[sa[i]]=cmp(y,sa[i-1],sa[i],j) ? p-1:p++;
    }
}

void calHeight(char *r, int *sa, int n){
    int i, j, k = 0;
    for(i = 1; i <= n; i++)  rk[sa[i]] = i;
    for(i = 0; i < n; i++){
        for(k? k--:0, j=sa[rk[i]-1]; r[i+k]==r[j+k]; k++);
        height[rk[i]] = k;
    }
}


AC自动机
struct node {
    int ct;
    node *pre, *next[26];
    void init() {
        ct = 0;
        pre = 0;
        memset(next, 0, sizeof(next));
    }
};

int cnt; //节点总数
node *root, trie[500010];

node *queue[500010];

void insertStr(node *root, char *str) {
    int index, len = strlen(str);
    for(int i = 0; i < len; i++) {
        index = str[i]-'a';
        if(root->next[index] == 0) {
            root->next[index] = &trie[++cnt];
            root->next[index]->init();
        }
        root = root->next[index];
    }
    root->ct++;
}

void buildAC() {
    int head, tail;
    node *u, tmp;
    queue[0] = root;
    root->pre = root;
    head = tail = 0;
    while(head <= tail) {
        u = queue[head++];
        for(int i = 0; i < 26; i++) {
            if(u->next[i] == 0) {
                if(u == root)  u->next[i] = root;
                else  u->next[i] = u->pre->next[i];
            }
            else {
                if(u == root)  u->next[i]->pre = root;
                else  u->next[i]->pre = u->pre->next[i];
                queue[++tail] = u->next[i];
            }
        }
    }
}

分数规划
(1) 一般分数规划的解法
简单总结一下解分数规划的一般步骤吧:
   1.对于最小化目标函数r = ax/bx,则构造函数g(r)=min{ax - r*bx}
     对于最大化目标函数r = ax/bx,等价于最小化目标函数bx/ax,因此同上。
   2.由各种大科学家大神们证明得结论T_T:
     (1)g(r)是单调减函数(有些离散情况下也有可能是单调不增加函数),即随r的增加而减小。 
     (2)若r是最优解,则g(r)==0。。
   3.建立模型二分r求解。

二分图最小权匹配
#include <iostream>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <vector>
#include <utility>
using namespace std;

const int N =105;
const int M =10005;
const int inf =0x1fffffff;

int n, m, tot, lx[N], ly[N], match[N], h[N], v[M], w[M], nxt[M];
bool visx[N], visy[N];
int lack;

void add(int a, int b, int c)
{
    v[tot] = b;
    w[tot] = c;
    nxt[tot] = h[a];
    h[a] = tot++;
}

bool find(int u)
{
    int i, t;
    visx[u] =true;
    for(i = h[u]; i !=-1; i = nxt[i])
        if(!visy[v[i]])
        {
            t = w[i] - lx[u] - ly[v[i]];
            if(t ==0)
            {
                visy[v[i]] =true;
                if(match[v[i]]==-1|| find(match[v[i]]))
                {
                    match[v[i]] = u;
                    return  true;
                }
            }
            else if(t >0)
                lack = min(lack, t);
        }
    return  false;
}

int calMatch(int n) {
    int ans = 0;
    for(int i =1; i <= n; i++)
    {
        lx[i] = inf;
        ly[i] =0;
        for(int j = h[i]; j !=-1; j = nxt[j])
            lx[i] = min(lx[i], w[j]);
    }
    memset(match, -1, sizeof(match));
    for(int i =1; i <= n; i++)
    {
        memset(visx, false, sizeof(visx));
        memset(visy, false, sizeof(visy));
        lack = inf;
        while(!find(i))
        {
            for(int j =1; j <= n; j++)
            {
                if(visx[j])  lx[j] += lack;
                if(visy[j])  ly[j] -= lack;
            }
            memset(visx, false, sizeof(visx));
            memset(visy, false, sizeof(visy));
        }
    }
    ans = 0;
    for(int i =1; i <= n; i++)  ans = ans + lx[i] + ly[i];
    return  ans;
}

二分图最大权匹配
#include <iostream>
#include <cstdio>
#include <cstring>
usingnamespace std;

constint N =310;
constint inf =0x1fffffff;

int n, lx[N], ly[N], match[N], w[N][N];
bool visx[N], visy[N];
int lack;

int getNum()
{
    char c;
    int ans =0;
    c = getchar();
    while(c<'0'|| c>'9') c = getchar();
    while(c>='0'&& c<='9')
    {
        ans = ans*10+c-'0';
        c = getchar();
    }
    return  ans;
}

bool find(int u)
{
    int i, t;
    visx[u] =true;
    for(i =1; i <= n; i++)
        if(!visy[i])
        {
            t = lx[u] + ly[i] - w[u][i];
            if(t ==0)
            {
                visy[i] =true;
                if(match[i]==-1|| find(match[i]))
                {
                    match[i] = u;
                    returntrue;
                }
            }
            elseif(t >0)
                lack = min(lack, t);
        }
    returnfalse;
}

int main()
{
    int i, j, ans;
    while(scanf("%d", &n) != EOF)
    {
        for(i =1; i <= n; i++)
        {
            lx[i] = ly[i] =0;
            for(j =1; j <= n; j++)
            {
                w[i][j] = getNum();
                lx[i] = max(lx[i], w[i][j]);
            }
        }
        memset(match, -1, sizeof(match));
        for(i =1; i <= n; i++)
        {
            memset(visx, false, sizeof(visx));
            memset(visy, false, sizeof(visy));
            lack = inf;
            while(!find(i))
            {
                for(j =1; j <= n; j++)
                {
                    if(visx[j])  lx[j] -= lack;
                    if(visy[j])  ly[j] += lack;
                }
                memset(visx, false, sizeof(visx));
                memset(visy, false, sizeof(visy));
            }
        }
        ans =0;
        for(i =1; i <= n; i++)  ans = ans + lx[i] + ly[i];
        printf("%d\n", ans);
    }
    return0;
}

2-SAT问题(判定+求解)
#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>
#include <algorithm>
using namespace std;

const int N = 1010;

int n; //原图中共有2*n个相对的节点。
int ct, depth, top, index[N<<1], d[N<<1], low[N<<1], stack[N<<1];
bool instack[N<<1], map[N<<1][N<<1], g[N<<1][N<<1];

int tot, et[N<<1], color[N<<1], op[N<<1];
bool visit[N<<1];

void initData() { //初始化数据,根据题意建图,建好的初始图为map
    ........
}

void dfs(int u) {    //tarjan求强连通分量,缩点
    int i, x;
    d[u] = low[u] = depth++;
    stack[++top] = u;
    instack[u] =true;
    for(i = 0; i < n+n; i++)
        if(map[u][i]) {
            if(d[i] == -1) {
                dfs(i);
                low[u] = min(low[u], low[i]);
            }
            else {
                if(instack[i])
                    low[u] = min(low[u], d[i]);
            }
        }
    if(low[u] == d[u]) {
        ct++;
        while(top)
        {
            x = stack[top--];
            instack[x] = false;
            index[x] = ct;
            if(x == u)  break;
        }
    }
}

void buildNewGraph() {  //根据缩点建立新图
    int i, j;
    memset(g, false, sizeof(g));
    for(i = 0; i < n+n; i++)
        for(j = 0; j < n+n; j++)
            if(map[i][j])
                g[index[i]][index[j]] = true;
    for(i = 1; i <= ct; i++)
        for(j = i+1; j <= ct; j++)
            swap(g[i][j], g[j][i]);   //将新图中的边反向
    for(i = 0; i < n; i++) {      //根据原图的矛盾节点确定新图的矛盾节点
        op[index[i]] = index[i+n];
        op[index[i+n]] = index[i];
    }
}

void transDfs(int u) {
    int i;
    visit[u] =true;
    for(i = 1; i <= ct; i++)
        if(!visit[i] && g[u][i])
            transDfs(i);
    et[++tot] = u;
}

void colorDfs(int u) {
    int i;
    color[u] = 0;
    for(i = 1; i <= ct; i++)
        if(color[i]==-1 && g[u][i])
            colorDfs(i);
}

void generateAns() {
    int i;
    memset(visit, false, sizeof(visit));
    tot = 0;
    //拓扑排序
    for(i = 1; i <= ct; i++)
        if(!visit[i])
            transDfs(i);
    memset(color, -1, sizeof(color));
    for(i = ct; i > 0; i--)
        if(color[et[i]] == -1) {
            color[et[i]] = 1;
            //选择第一个未着色的顶点x, 把x染成红色1, 并把与之矛盾的节点y及其所有子孙节点染成蓝色0。
            colorDfs(op[et[i]]);
        }
}

void solve() {
    int i;
    depth = top = ct =0;
    memset(d, -1, sizeof(d));
    memset(instack, false, sizeof(instack));
    for(i = 0; i < n+n; i++)
        if(d[i] == -1)
            dfs(i);
    for(i = 0; i < n; i++)
        if(index[i] == index[i+n])
            break;
    if(i < n)  printf("NO\n");
    else {
        printf("YES\n");
        buildNewGraph();
        generateAns();
        //printAns();
    }
}

int main()
{
    initData();
    solve();
    return  0;
}

最大流-dinic
#include <iostream>
#include <cstdio>
#include <string>
#include <vector>
#include <cstring>
#include <utility>
#include <algorithm>
using namespace std;

const int Maxn = 20005;
const int Maxm = (200005<<1)+(Maxn<<1);
const int inf = 0x1fffffff;

int n, m, queue[Maxn], lab[Maxn];
int tot, h[Maxn], nxt[Maxm<<1], v[Maxm<<1], res[Maxm<<1];

void addEdge(int a, int b, int c) {
    v[tot] = b; res[tot] = c; nxt[tot] = h[a]; h[a] = tot++;
    v[tot] = a; res[tot] = 0; nxt[tot] = h[b]; h[b] = tot++;
}

bool bfs(int s, int t) {
    int head, tail, u;
    memset(lab, -1, sizeof(lab));
    lab[s] = head = tail =0;
    queue[0] = s;
    while(head <= tail) {
        u = queue[head++];
        for(int i = h[u]; i != -1; i = nxt[i])
            if(res[i]>0 && lab[v[i]]==-1) {
                lab[v[i]] = lab[u] +1;
                queue[++tail] = v[i];
            }
    }
    if(lab[t] != -1)  return  true;
    else  return  false;
}

int dinicDfs(int delta, int u, int t) {
    int sum =0, tmp;
    if(u == t)  return  delta;
    else {
        for(int i = h[u]; i != -1; i = nxt[i])
            if(lab[v[i]]==lab[u]+1 && res[i]>0) {
                tmp = dinicDfs(min(delta, res[i]), v[i], t);
                sum += tmp;
                delta -= tmp;
                res[i] -= tmp;
                res[i^1] += tmp;
                if(delta == 0)  break;
            }
        if(sum == 0)  lab[u] = -1;
        return  sum;
    }
}

int maxFlow(int s, int t) {
    int ans =0;
    while(bfs(s, t))
        ans += dinicDfs(inf, s, t);
    return  ans;
}

int main()
{
    int a, b, c, s, t;
    freopen("data.txt", "r", stdin);
    while(scanf("%d%d", &n, &m) != EOF) {
        s = 0; t = n+1;
        tot = 0;
        for(int i = 0; i <= t; i++)  h[i] = -1;
        for(int i = 1; i <= n; i++) {
            scanf("%d%d", &a, &b);
            addEdge(s, i, a); addEdge(i, t, b);
        }
        while(m--) {
            scanf("%d%d%d", &a, &b, &c);
            addEdge(a, b, c); addEdge(b, a, c);
        }
        int ans = maxFlow(s, t);
        cout << ans << endl;
    }
    return  0;
}

最短路径(spfa判负环)
#include <iostream>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <vector>
#include <queue>
#include <algorithm>
using namespace std;

const int N = 550;
const int M = 3000<<1;

int Case, n, m, w;
int tot, h[N], nxt[M], c[M], v[M];
int used[N], dis[N];
bool visit[N];

void add(int s, int t, int e) {
    v[tot] = t; c[tot] = e;
    nxt[tot] = h[s]; h[s] = tot++;
}

bool spfa(int s) {
    int u;
    queue <int> q; while(!q.empty())  q.pop();
    memset(visit, false, sizeof(visit));
    memset(used, 0, sizeof(used));
    for(int i = 1; i <= n; i++)  dis[i] = 0x1fffffff; dis[0] = 0;
    used[0] = 1;
    q.push(s);
    while(!q.empty()) {
        u = q.front(); q.pop();
        visit[u] = false;
        for(int p = h[u]; p != -1; p = nxt[p]) {
            if(dis[v[p]] > dis[u] + c[p]) {
                dis[v[p]] = dis[u] + c[p];
                if(!visit[v[p]]) {
                    visit[v[p]] = true;
                    q.push(v[p]);
                    used[v[p]]++;
                    if(used[v[p]] >= n)  return  true;
                }
            }
        }
    }
    return  false;
}

int main() {
    int s, t, e;
    scanf("%d", &Case);
    while(Case--) {
        scanf("%d%d%d", &n, &m, &w);
        memset(h, -1, sizeof(h)); tot = 0;
        for(int i = 0; i < m; i++) {
            scanf("%d%d%d", &s, &t, &e);
            add(s, t, e);
            add(t, s, e);
        }
        for(int i = 0; i < w; i++) {
            scanf("%d%d%d", &s, &t, &e);
            add(s, t, -e);
        }
        for(int i = 1; i <= n; i++)  add(0, i, 0);
        if(spfa(0))  printf("YES\n");
        else  printf("NO\n");
    }
    return  0;
}

最小生成树 (kruskal、并查集)
#include <iostream>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <vector>
#include <algorithm>
using namespace std;

const int N = 200010;

struct node {
    int x, y, cost;
}e[N];
int n, m, father[N];

bool cmp(const node &a, const node &b) {
    return  a.cost < b.cost;
}

int getFather(int u) {
    if(father[u] != u)  father[u] = getFather(father[u]);
    return  father[u];
}

int kruskal() {
    int fa, fb, sum = 0;
    for(int i = 0; i < n; i++)  father[i] = i;
    sort(e, e+m, cmp);
    for(int i = 0; i < m; i++) {
        fa = getFather(e[i].x); fb = getFather(e[i].y);
        if(fa == fb)  continue;
        else {
            father[fb] = father[fa];
            sum += e[i].cost;
        }
    }
    return  sum;
}

int main() {
    int tot;
    freopen("data.in", "r", stdin);
    while(scanf("%d%d", &n, &m) != EOF) {
        if(n==0 && m==0)  break;
        tot = 0;
        for(int i = 0; i < m; i++) {
            scanf("%d%d%d", &e[i].x, &e[i].y, &e[i].cost);
            tot += e[i].cost;
        }
        int ans = tot-kruskal();
        printf("%d\n", ans);
    }
    return  0;
}

最小生成树prim
#include <iostream>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <vector>
#include <queue>
#include <algorithm>
using namespace std;

const int N = 105;

int Case, n;
bool visit[N];
double x[N], y[N], dis[N], g[N][N];

double Cal(int a, int b) {
    double tx=x[a]-x[b], ty=y[a]-y[b];
    return  sqrt(tx*tx + ty*ty);
}

double prim() {
    double tot = 0.0, min;
    int v;
    for(int i = 1; i <= n; i++)  dis[i] = g[1][i];
    memset(visit, false, sizeof(visit));
    visit[1] = true;
    for(int k = 1; k < n; k++) {
        min = 1e8;
        for(int i = 1; i <= n; i++) {
            if(!visit[i] && min>dis[i]) {
                min = dis[i];
                v = i;
            }
        }
        visit[v] = true;
        for(int i = 1; i <= n; i++) {
            if(!visit[i] && dis[i]>g[v][i]) {
                dis[i] = g[v][i];
            }
        }
        tot += min;
    }
    return  tot;
}

int main() {
    freopen("data.in", "r", stdin);
    scanf("%d", &Case);
    while(Case--) {
        scanf("%d", &n);
        for(int i = 1; i <= n; i++)  scanf("%lf%lf", &x[i], &y[i]);
        for(int i = 1; i <= n; i++) {
            g[i][i] = 0.0;
            for(int j = i+1; j <= n; j++) {
                g[i][j] = g[j][i] = Cal(i, j);
            }
        }
        double ans = prim();
        printf("%.2f\n", ans);
        if(Case)  printf("\n");
    }
    return  0;
}

stl优先队列的简单用法
#include <iostream>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <vector>
#include <queue>
#include <algorithm>
using namespace std;

struct comp {
    bool operator () (int a, int b) {
        return  a > b;
    }
};

int main() {
    freopen("data.in", "r", stdin);
    priority_queue <int, vector<int>, comp> q;
    q.push(11); q.push(0); q.push(22); q.push(16); q.push(6); q.push(8); q.push(100);
    while(!q.empty()) {
        int x = q.top(); q.pop();
        cout << x << endl;
    }
    return  0;
}

输出:
6
11
22

二分图最大匹配

int n, match[N];
bool visit[N], g[N][N];

bool find(int u) {
    for(int i = 0; i < m; i++) {
        if(g[u][i] && !visit[i]) {
            visit[i] = true;
            if(match[i]==-1 || find(match[i])) {
                match[i] = u;
                return  true;
            }
        }
    }
    return  false;
}

int maxMatch() {
    int ans = 0;
    memset(match, -1, sizeof(match));
    for(int i = 0; i < n; i++) {
        if(find(i))  ans++;
        memset(visit, false, sizeof(visit));
    }
    return  ans;
}

康托展开
#include <iostream>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <vector>
#include <algorithm>
using namespace std;

const int N = 10;

int p[N], fac[N];

int Cal(int p[], int n) {
    int ans = 0;
    for(int i = 0; i < n; i++) {
        int ct = 0;
        for(int j = i+1; j < n; j++) {
            if(p[j] < p[i])  ct++;
        }
        ans += ct*fac[n-i-1];
    }
    return  ans+1;
}

int main() {
    int n;
    fac[0] = 1;
    for(int i = 1; i < N; i ++)  fac[i] = fac[i-1]*i;
    while(cin >> n) {
        for(int i = 0; i < n; i++)  cin >> p[i];
        int ans = Cal(p, n);
        cout << ans << endl;
    }
    return  0;
}

最小费用(最大)流
#include <iostream>
#include <algorithm>
#include <string>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <queue>
#include <vector>
#include <cmath>
using namespace std;
int sumFlow;
const int MAXN = 1010;
const int MAXM = 1000200;
const int INF = 1000000000;
struct Edge
{
    int u, v, cap, cost;
    int next;
}edge[MAXM<<2];
int NE;
int head[MAXN], dist[MAXN], pp[MAXN];
bool vis[MAXN];
void init()
{
    NE = 0;
    memset(head, -1, sizeof(head));
}
void addedge(int u, int v, int cap, int cost)
{
    edge[NE].u = u; edge[NE].v = v; edge[NE].cap = cap; edge[NE].cost = cost;
    edge[NE].next = head[u]; head[u] = NE++;
    edge[NE].u = v; edge[NE].v = u; edge[NE].cap = 0; edge[NE].cost = -cost;
    edge[NE].next = head[v]; head[v] = NE++;
}
bool SPFA(int s, int t, int n)
{
    int i, u, v;
    queue <int> qu;
    memset(vis,false,sizeof(vis));
    memset(pp,-1,sizeof(pp));
    for(i = 0; i <= n; i++) dist[i] = INF;
    vis[s] = true; dist[s] = 0;
    qu.push(s);
    while(!qu.empty())
    {
        u = qu.front(); qu.pop(); vis[u] = false;
        for(i = head[u]; i != -1; i = edge[i].next)
        {
            v = edge[i].v;
            if(edge[i].cap && dist[v] > dist[u] + edge[i].cost)
            {
                dist[v] = dist[u] + edge[i].cost;
                pp[v] = i;
                if(!vis[v])
                {
                    qu.push(v);
                    vis[v] = true;
                }
            }
        }
    }
    if(dist[t] == INF) return false;
    return true;
}
int MCMF(int s, int t, int n) // minCostMaxFlow
{
    int flow = 0; // 总流量
    int i, minflow, mincost;
    mincost = 0;
    while(SPFA(s, t, n))
    {
        minflow = INF + 1;
        for(i = pp[t]; i != -1; i = pp[edge[i].u])
            if(edge[i].cap < minflow)
                minflow = edge[i].cap;
        flow += minflow;
        for(i = pp[t]; i != -1; i = pp[edge[i].u])
        {
            edge[i].cap -= minflow;
            edge[i^1].cap += minflow;
        }
        mincost += dist[t] * minflow;
    }
    sumFlow = flow; // 最大流
    return mincost;
}

日期类
int days[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
class Date {
public:
    //判断是否闰年
    inline static bool isLeap(int year) {
        return (year % 4 == 0 && year % 100 != 0) || year % 400 == 0;
    }
    int year, month, day;
    Date() {}
    Date(int y, int m, int d) : year(y), month(m), day(d) {}
    //判断日期是否合法
    inline bool isLegal() const {
        if (month <= 0 || month > 12) {
            return false;
        }
        if (month == 2) {
            return day > 0 && day <= 28 + isLeap(year);
        }
        return day > 0 && day <= days[month - 1];
    }
    //与另一个日期比较
    inline int compareTo(const Date &other) const {
        if (year != other.year) {
            return year - other.year;
        }
        if (month != other.month) {
            return month - other.month;
        }
        return day - other.day;
    }
    //返回当前日期是星期几 0 (Sunday) ... 6 (Saturday)
    inline int toWeekday() const {
        int tm = month >= 3 ? (month - 2) : (month + 10);
        int ty = month >= 3 ? year : (year - 1);
        return (ty + ty / 4 - ty / 100 + ty / 400 + (int)(2.6 * tm - 0.2) + day) % 7;
    }
    //将日期转换为偏移量
    inline int toInt() const {
        int ret = year * 365 + (year - 1) / 4 - (year - 1) / 100 + (year - 1) / 400;
        days[1] += isLeap(year);
        for (int i = 0; i < month - 1; ret += days[i++]);
        days[1] = 28;
        return ret + day;
    }
    //根据给定的偏移量设置当前日期
    inline void fromInt(int a) {
        year = a / 146097 * 400;
        for (a %= 146097; a >= 365 + isLeap(year); a -= 365 + isLeap(year), year++);
        days[1] += isLeap(year);
        for (month = 1; a >= days[month - 1]; a -= days[month - 1], month++);
        days[1] = 28;
        day = a + 1;
    }
};

不带size域的treap
// 不带size域的treap
class Treap {
public:
    const static int MaxN = 100000;
    int root, tsize, l[MaxN], r[MaxN], p[MaxN];
    int key[MaxN];

    void rot_l(int &x) {    //before using this function, please ensure that the right son of x exist
        int tmp = r[x];
        r[x] = l[tmp]; l[tmp] = x;
        x = tmp;
    }
    void rot_r(int &x) {    //before using this function, please ensure that the left son of x exist
        int tmp = l[x];
        l[x] = r[tmp]; r[tmp] = x;
        x = tmp;
    }
    Treap():root(-1),tsize(-1) {}
    void insert(int &root, const int &x) {
        if(root == -1) {
            key[++tsize] = x;
            root = tsize;
            p[root] = rand();
            l[root] = r[root] = -1;
        }
        else if(x <= key[root]) {
            insert(l[root], x);
            if(p[l[root]] > p[root])  rot_r(root);
        }
        else {
            insert(r[root], x);
            if(p[r[root]] > p[root])  rot_l(root);
        }
    }
    void del(int &root, const int &x) {
        if(key[root] == x) {
            if(l[root]==-1 && r[root]==-1)  root = -1;
            else if(l[root] == -1)  root = r[root];
            else if(r[root] == -1)  root = l[root];
            else {
                if(p[l[root]] > p[r[root]]) {
                    rot_r(root);
                    del(r[root], x);
                }
                else {
                    rot_l(root);
                    del(l[root], x);
                }
            }
        }
        else if(x < key[root])  del(l[root], x);
        else del(r[root], x);
    }
    bool find(int &root, const int &x) {
        if(root == -1)  return  false;
        if(x == key[root])  return  true;
        else if(x < key[root])  return  find(l[root], x);
        else return  find(r[root], x);
    }
};

带size域的treap
//带size的treap
class Treap {
public:
    const static int MaxN = 100000;
    int root, tsize, l[MaxN], r[MaxN], p[MaxN], nsize[MaxN];
    int key[MaxN];

    void maintain(const int &root) {
        int ta, tb;
        ta = l[root]==-1? 0 : nsize[l[root]];
        tb = r[root]==-1? 0 : nsize[r[root]];
        nsize[root] = ta+tb+1;
    }
    void rot_l(int &x) {    //before using this function, please ensure that the right son of x exist
        int tmp = r[x];
        r[x] = l[tmp]; maintain(x);
        l[tmp] = x; x = tmp; maintain(x);
    }
    void rot_r(int &x) {    //before using this function, please ensure that the left son of x exist
        int tmp = l[x];
        l[x] = r[tmp]; maintain(x);
        r[tmp] = x; x = tmp; maintain(x);
    }
    Treap():root(-1),tsize(-1) {}
    void insert(int &root, const int &x) {
        if(root == -1) {
            key[++tsize] = x;
            root = tsize;
            p[root] = rand();
            l[root] = r[root] = -1;
            nsize[root] = 1;
        }
        else if(x <= key[root]) {
            insert(l[root], x);
            if(p[l[root]] > p[root])  rot_r(root);
        }
        else {
            insert(r[root], x);
            if(p[r[root]] > p[root])  rot_l(root);
        }
        maintain(root);
    }
    void del(int &root, const int &x) {
        if(key[root] == x) {
            if(l[root]==-1 && r[root]==-1)  root = -1;
            else if(l[root] == -1)  root = r[root];
            else if(r[root] == -1)  root = l[root];
            else {
                if(p[l[root]] > p[r[root]]) {
                    rot_r(root);
                    del(r[root], x);
                }
                else {
                    rot_l(root);
                    del(l[root], x);
                }
            }
        }
        else if(x < key[root])  del(l[root], x);
        else del(r[root], x);
        if(root != -1)  maintain(root);
    }
    int kthElement(const int &root, int k) {
        int ta;
        ta = l[root]==-1? 0 : nsize[l[root]];
        if(ta >= k)  return  kthElement(l[root], k);
        else if(ta+1 == k)  return  key[root];
        else  return  kthElement(r[root], k-ta-1);
    }
    bool find(int &root, const int &x) {
        if(root == -1)  return  false;
        if(x == key[root])  return  true;
        else if(x < key[root])  return  find(l[root], x);
        else return  find(r[root], x);
    }
};

Splay Top-down实现
class SplayTree
{
public:
    SplayTree();
    int getMaxValure();
    int getMinValure();
    void deleteElement(const int &x);
    void insertElement(const int &x);
    bool findElement(const int &x);
    int preElement(const int &x);
    int succElement(const int &x);
private:
    struct node
    {
        int key;
        node *lchild, *rchild;
        node(){}
        node(const int &x):key(x) {}
    }*root, *nullnode;
    void Zig(node *&x);  //右旋
    void Zag(node *&x);  //左旋
    void splay(node *&root, const int &x);
};
SplayTree::SplayTree()
{
    nullnode = new node();
    nullnode->lchild = nullnode;
    nullnode->rchild = nullnode;
    root = nullnode;
}
int SplayTree::getMaxValure()
{
    node *p = root;
    while(p->rchild != nullnode)  p = p->rchild;
    splay(root, p->key);
    return  p->key;
}
int SplayTree::getMinValure()
{
    node *p = root;
    while(p->lchild != nullnode)  p = p->lchild;
    splay(root, p->key);
    return  p->key;
}
void SplayTree::deleteElement(const int &x)
{
    node *newnode;
    splay(root, x);
    if(root->key != x)  return;
    if(root->lchild == nullnode)
        newnode = root->rchild;
    else
    {
        newnode = root->lchild;
        splay(newnode, x);
        newnode->rchild = root->rchild;
    }
    delete root;
    root = newnode;
}
void SplayTree::insertElement(const int &x)
{
    node *newnode = new node(x);
    if(root == nullnode)
    {
        root = newnode;
        root->lchild = nullnode;
        root->rchild = nullnode;
        return;
    }
    splay(root, x);
    if(x < root->key)
    {
        newnode->lchild = root->lchild;
        root->lchild = nullnode;
        newnode->rchild = root;
        root = newnode;
    }
    else
    {
        newnode->rchild = root->rchild;
        root->rchild = nullnode;
        newnode->lchild = root;
        root = newnode;
    }
}
void SplayTree::Zig(node *&x)
{
    node *y = x->lchild;
    x->lchild = y->rchild;
    y->rchild = x;
    x = y;
}
void SplayTree::Zag(node *&x)
{
    node *y = x->rchild;
    x->rchild = y->lchild;
    y->lchild = x;
    x = y;
}
void SplayTree::splay(node *&root, const int &x)
{
    node headnode;
    node *ltree, *rtree;
    headnode.lchild = headnode.rchild = nullnode;
    ltree = rtree = &headnode;
    while(root->key != x)
    {
        if(x < root->key)
        {
            if(root->lchild!=nullnode && x<root->lchild->key)
                Zig(root);
            if(root->lchild == nullnode)  break;
            rtree->lchild = root;
            rtree = root;
            root = root->lchild;
        }
        else
        {
            if(root->rchild!=nullnode && root->rchild->key<x)
                Zag(root);
            if(root->rchild == nullnode)  break;
            ltree->rchild = root;
            ltree = root;
            root = root->rchild;
        }
    }
    ltree->rchild = root->lchild;
    root->lchild = headnode.rchild;
    rtree->lchild = root->rchild;
    root->rchild = headnode.lchild;
}
bool SplayTree::findElement(const int &x)
{
    splay(root, x);
    if(root->key == x)  return  true;
    else  return  false;
}
int SplayTree::preElement(const int &x)
{
    int ans = 0;
    splay(root, x);
    node *p = root;
    while(p != nullnode)
    {
        if(p->key < x)
        {
            ans = p->key;
            p = p->rchild;
        }
        else  p = p->lchild;
    }
    return  ans;
}
int SplayTree::succElement(const int &x)
{
    int ans = 0x1fffffff;
    splay(root, x);
    node *p = root;
    while(p != nullnode)
    {
        if(p->key > x)
        {
            ans = p->key;
            p = p->lchild;
        }
        else  p = p->rchild;
    }
    return  ans;
}

自适应辛普森公式
#include <cmath>
#include <cstdio>
#include <cstring>
#include <string>
#include <vector>
#include <utility>
#include <iostream>
#include <algorithm>
using namespace std;

typedef long long llg;

//本函数在模板中无意义,需根据不同的积分表达式编写
double F(double x) {
    return  x;
}

double simpson(double a, double b) {
    double c = (a+b)/2;
    return  (F(a)+4*F(c)+F(b))*(b-a)/6;
}

double asr(double a, double b, double eps, double A) {
    double c = (a+b)/2;
    double L = simpson(a, c), R = simpson(c, b);
    if(fabs(L+R-A) <= 15*eps)  return  L+R+(L+R-A)/15.0;
    return  asr(a, c, eps/2, L) + asr(c, b, eps/2, R);
}

double asr(double a, double b, double eps) {
    return  asr(a, b, eps, simpson(a, b));
}

int main() {
    freopen("data.in", "r", stdin);
    cout << asr(0, 1, 1e-5) << endl;
    return  0;
}

素数测试和因子分解
#include <iostream>
#include <ctime>
#include <cstdio>
#include <cstdlib>
#include <cstring>
using namespace std;

typedef longlong llg;

const int S =70;

llg tot, p[80];

llg mullg(llg a, llg b, llg n)
{
    llg ans =0, tmp = a%n;
    while(b)
    {
        if(b &1)  ans += tmp;
        if(ans >= n)  ans -= n;
        b >>=1;
        tmp <<=1;
        if(tmp >= n)  tmp -= n;
    }
    return  ans;
}

llg powMod(llg a, llg b, llg n)
{
    llg ans =1, tmp = a % n;
    while(b)
    {
        if(b &1)  ans = mullg(ans, tmp, n);
        b >>=1;
        tmp = mullg(tmp, tmp, n);
    }
    return  ans;
}

bool witness(llg a, llg n)
{
    int i, t =0;
    llg x, tx, nn = n-1;
    while((nn&1) ==0)
    {
        nn >>=1;
        t++;
    }
    x = powMod(a, nn, n);
    for(i =1; i <= t; i++)
    {
        tx = mullg(x, x, n);
        if(tx==1&& x!=1&& x!=n-1)
            return  true;
        x = tx;
    }
    if(x !=1)  return  true;
    return  false;
}

bool millerRabin(llg n)
{
    int i;
    llg a;
    if(n <2)  return  false;
    if(n ==2)  return  true;
    for(i =1; i <= S; i++)
    {
        a = (llg)rand()%(n-1) +1;
        if(witness(a, n))
            return  false;
    }
    return  true;
}

llg Abs(llg x)
{
    if(x <0)  x =-x;
    return  x;
}

llg gcd(llg a, llg b)
{
    if(b ==0)  return  a;
    else return  gcd(b, a%b);
}

llg pollardRho(llg n, int c)
{
    int i =0;
    llg x, y, k, d;
    y = x = rand()%(n-1) +1;
    k =2;
    while(1)
    {
        i++;
        x = (mullg(x, x, n)+c) % n;
        d = gcd(Abs(y-x), n);
        if(d!=1&& d!=n)  return  d;
        if(y == x)  return  n;
        if(i == k)
        {
            y = x;
            k <<=1;
        }
    }
}

void findFac(llg n)
{
    if(millerRabin(n))
    {
        p[tot++] = n;
        return;
    }
    else
    {
        //if(depth > 100)  return;
        llg p = n;
        while(p==n && p)  p = pollardRho(p, rand()%(n-1)+1);
        findFac(p);
        findFac(n/p);
    }
}
}}}
关键词: 后缀数组  AC自动机   AC+dp    分数规划    二分图最小权    二分图最大权  2-sat    最大流     最短路径(负环判定)    
最小生成树(kruskal、并查集)    最小生成树prim    stl优先队列的简单用法   二分图最大匹配     康托展开  最小费用(最大)流    日期
Treap Splay 辛普森  因子分解
后缀数组
const int N = 40005;
int sa[N], rk[N], height[N];
int wa[N], wb[N], wv[N], wts[N];
inline bool cmp(int *r, int a, int b, int len) {
    return (r[a]==r[b]) && (r[a+len]==r[b+len]);
}
void sortSA(char *r, int *sa, int n, int m){
    int i, j, p, *x = wa, *y = wb, *t;
    for(i = 0; i < m; i++)
        wts[i] = 0;
    for(i = 0; i < n; i++)
        wts[x[i]=r[i]]++;
    for(i = 1; i < m; i++)
        wts[i] += wts[i-1];
    for(i = n-1; i >= 0; i--)
        sa[--wts[x[i]]] = i;
    for(j = p = 1; p < n; j <<= 1, m = p){
        for(p=0, i=n-j; i < n; i++)
            y[p++] = i;
        for(i = 0; i < n; i++){
            if(sa[i] >= j)
                y[p++] = sa[i] - j;
        }
        for(i = 0; i < m; i++)
            wts[i] = 0;
        for(i = 0; i < n; i++)
            wts[wv[i]=x[y[i]]]++;
        for(i = 1; i < m; i++)
            wts[i] += wts[i-1];
        for(i = n-1; i >= 0; i--)
            sa[--wts[wv[i]]] = y[i];
        for(t=x,x=y,y=t,x[sa[0]]=0,p=i=1; i < n; i++)
            x[sa[i]]=cmp(y,sa[i-1],sa[i],j) ? p-1:p++;
    }
}
void calHeight(char *r, int *sa, int n){
    int i, j, k = 0;
    for(i = 1; i <= n; i++)  rk[sa[i]] = i;
    for(i = 0; i < n; i++){
        for(k? k--:0, j=sa[rk[i]-1]; r[i+k]==r[j+k]; k++);
        height[rk[i]] = k;
    }
}
AC自动机
struct node {
    int ct;
    node *pre, *next[26];
    void init() {
        ct = 0;
        pre = 0;
        memset(next, 0, sizeof(next));
    }
};
int cnt; //节点总数
node *root, trie[500010];
node *queue[500010];
void insertStr(node *root, char *str) {
    int index, len = strlen(str);
    for(int i = 0; i < len; i++) {
        index = str[i]-'a';
        if(root->next[index] == 0) {
            root->next[index] = &trie[++cnt];
            root->next[index]->init();
        }
        root = root->next[index];
    }
    root->ct++;
}
void buildAC() {
    int head, tail;
    node *u, tmp;
    queue[0] = root;
    root->pre = root;
    head = tail = 0;
    while(head <= tail) {
        u = queue[head++];
        for(int i = 0; i < 26; i++) {
            if(u->next[i] == 0) {
                if(u == root)  u->next[i] = root;
                else  u->next[i] = u->pre->next[i];
            }
            else {
                if(u == root)  u->next[i]->pre = root;
                else  u->next[i]->pre = u->pre->next[i];
                queue[++tail] = u->next[i];
            }
        }
    }
}
分数规划
(1) 一般分数规划的解法
简单总结一下解分数规划的一般步骤吧:
   1.对于最小化目标函数r = ax/bx,则构造函数g(r)=min{ax - r*bx}
     对于最大化目标函数r = ax/bx,等价于最小化目标函数bx/ax,因此同上。
   2.由各种大科学家大神们证明得结论T_T:
     (1)g(r)是单调减函数(有些离散情况下也有可能是单调不增加函数),即随r的增加而减小。 
     (2)若r是最优解,则g(r)==0。。
   3.建立模型二分r求解。
二分图最小权匹配
#include <iostream>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <vector>
#include <utility>
using namespace std;
const int N =105;
const int M =10005;
const int inf =0x1fffffff;
int n, m, tot, lx[N], ly[N], match[N], h[N], v[M], w[M], nxt[M];
bool visx[N], visy[N];
int lack;
void add(int a, int b, int c)
{
    v[tot] = b;
    w[tot] = c;
    nxt[tot] = h[a];
    h[a] = tot++;
}
bool find(int u)
{
    int i, t;
    visx[u] =true;
    for(i = h[u]; i !=-1; i = nxt[i])
        if(!visy[v[i]])
        {
            t = w[i] - lx[u] - ly[v[i]];
            if(t ==0)
            {
                visy[v[i]] =true;
                if(match[v[i]]==-1|| find(match[v[i]]))
                {
                    match[v[i]] = u;
                    return  true;
                }
            }
            else if(t >0)
                lack = min(lack, t);
        }
    return  false;
}
int calMatch(int n) {
    int ans = 0;
    for(int i =1; i <= n; i++)
    {
        lx[i] = inf;
        ly[i] =0;
        for(int j = h[i]; j !=-1; j = nxt[j])
            lx[i] = min(lx[i], w[j]);
    }
    memset(match, -1, sizeof(match));
    for(int i =1; i <= n; i++)
    {
        memset(visx, false, sizeof(visx));
        memset(visy, false, sizeof(visy));
        lack = inf;
        while(!find(i))
        {
            for(int j =1; j <= n; j++)
            {
                if(visx[j])  lx[j] += lack;
                if(visy[j])  ly[j] -= lack;
            }
            memset(visx, false, sizeof(visx));
            memset(visy, false, sizeof(visy));
        }
    }
    ans = 0;
    for(int i =1; i <= n; i++)  ans = ans + lx[i] + ly[i];
    return  ans;
}
二分图最大权匹配
#include <iostream>
#include <cstdio>
#include <cstring>
usingnamespace std;
constint N =310;
constint inf =0x1fffffff;
int n, lx[N], ly[N], match[N], w[N][N];
bool visx[N], visy[N];
int lack;
int getNum()
{
    char c;
    int ans =0;
    c = getchar();
    while(c<'0'|| c>'9') c = getchar();
    while(c>='0'&& c<='9')
    {
        ans = ans*10+c-'0';
        c = getchar();
    }
    return  ans;
}
bool find(int u)
{
    int i, t;
    visx[u] =true;
    for(i =1; i <= n; i++)
        if(!visy[i])
        {
            t = lx[u] + ly[i] - w[u][i];
            if(t ==0)
            {
                visy[i] =true;
                if(match[i]==-1|| find(match[i]))
                {
                    match[i] = u;
                    returntrue;
                }
            }
            elseif(t >0)
                lack = min(lack, t);
        }
    returnfalse;
}
int main()
{
    int i, j, ans;
    while(scanf("%d", &n) != EOF)
    {
        for(i =1; i <= n; i++)
        {
            lx[i] = ly[i] =0;
            for(j =1; j <= n; j++)
            {
                w[i][j] = getNum();
                lx[i] = max(lx[i], w[i][j]);
            }
        }
        memset(match, -1, sizeof(match));
        for(i =1; i <= n; i++)
        {
            memset(visx, false, sizeof(visx));
            memset(visy, false, sizeof(visy));
            lack = inf;
            while(!find(i))
            {
                for(j =1; j <= n; j++)
                {
                    if(visx[j])  lx[j] -= lack;
                    if(visy[j])  ly[j] += lack;
                }
                memset(visx, false, sizeof(visx));
                memset(visy, false, sizeof(visy));
            }
        }
        ans =0;
        for(i =1; i <= n; i++)  ans = ans + lx[i] + ly[i];
        printf("%d\n", ans);
    }
    return0;
}
2-SAT问题(判定+求解)
#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>
#include <algorithm>
using namespace std;
const int N = 1010;
int n; //原图中共有2*n个相对的节点。
int ct, depth, top, index[N<<1], d[N<<1], low[N<<1], stack[N<<1];
bool instack[N<<1], map[N<<1][N<<1], g[N<<1][N<<1];
int tot, et[N<<1], color[N<<1], op[N<<1];
bool visit[N<<1];
void initData() { //初始化数据,根据题意建图,建好的初始图为map
    ........
}
void dfs(int u) {    //tarjan求强连通分量,缩点
    int i, x;
    d[u] = low[u] = depth++;
    stack[++top] = u;
    instack[u] =true;
    for(i = 0; i < n+n; i++)
        if(map[u][i]) {
            if(d[i] == -1) {
                dfs(i);
                low[u] = min(low[u], low[i]);
            }
            else {
                if(instack[i])
                    low[u] = min(low[u], d[i]);
            }
        }
    if(low[u] == d[u]) {
        ct++;
        while(top)
        {
            x = stack[top--];
            instack[x] = false;
            index[x] = ct;
            if(x == u)  break;
        }
    }
}
void buildNewGraph() {  //根据缩点建立新图
    int i, j;
    memset(g, false, sizeof(g));
    for(i = 0; i < n+n; i++)
        for(j = 0; j < n+n; j++)
            if(map[i][j])
                g[index[i]][index[j]] = true;
    for(i = 1; i <= ct; i++)
        for(j = i+1; j <= ct; j++)
            swap(g[i][j], g[j][i]);   //将新图中的边反向
    for(i = 0; i < n; i++) {      //根据原图的矛盾节点确定新图的矛盾节点
        op[index[i]] = index[i+n];
        op[index[i+n]] = index[i];
    }
}
void transDfs(int u) {
    int i;
    visit[u] =true;
    for(i = 1; i <= ct; i++)
        if(!visit[i] && g[u][i])
            transDfs(i);
    et[++tot] = u;
}
void colorDfs(int u) {
    int i;
    color[u] = 0;
    for(i = 1; i <= ct; i++)
        if(color[i]==-1 && g[u][i])
            colorDfs(i);
}
void generateAns() {
    int i;
    memset(visit, false, sizeof(visit));
    tot = 0;
    //拓扑排序
    for(i = 1; i <= ct; i++)
        if(!visit[i])
            transDfs(i);
    memset(color, -1, sizeof(color));
    for(i = ct; i > 0; i--)
        if(color[et[i]] == -1) {
            color[et[i]] = 1;
            //选择第一个未着色的顶点x, 把x染成红色1, 并把与之矛盾的节点y及其所有子孙节点染成蓝色0。
            colorDfs(op[et[i]]);
        }
}
void solve() {
    int i;
    depth = top = ct =0;
    memset(d, -1, sizeof(d));
    memset(instack, false, sizeof(instack));
    for(i = 0; i < n+n; i++)
        if(d[i] == -1)
            dfs(i);
    for(i = 0; i < n; i++)
        if(index[i] == index[i+n])
            break;
    if(i < n)  printf("NO\n");
    else {
        printf("YES\n");
        buildNewGraph();
        generateAns();
        //printAns();
    }
}
int main()
{
    initData();
    solve();
    return  0;
}
最大流-dinic
#include <iostream>
#include <cstdio>
#include <string>
#include <vector>
#include <cstring>
#include <utility>
#include <algorithm>
using namespace std;
const int Maxn = 20005;
const int Maxm = (200005<<1)+(Maxn<<1);
const int inf = 0x1fffffff;
int n, m, queue[Maxn], lab[Maxn];
int tot, h[Maxn], nxt[Maxm<<1], v[Maxm<<1], res[Maxm<<1];
void addEdge(int a, int b, int c) {
    v[tot] = b; res[tot] = c; nxt[tot] = h[a]; h[a] = tot++;
    v[tot] = a; res[tot] = 0; nxt[tot] = h[b]; h[b] = tot++;
}
bool bfs(int s, int t) {
    int head, tail, u;
    memset(lab, -1, sizeof(lab));
    lab[s] = head = tail =0;
    queue[0] = s;
    while(head <= tail) {
        u = queue[head++];
        for(int i = h[u]; i != -1; i = nxt[i])
            if(res[i]>0 && lab[v[i]]==-1) {
                lab[v[i]] = lab[u] +1;
                queue[++tail] = v[i];
            }
    }
    if(lab[t] != -1)  return  true;
    else  return  false;
}
int dinicDfs(int delta, int u, int t) {
    int sum =0, tmp;
    if(u == t)  return  delta;
    else {
        for(int i = h[u]; i != -1; i = nxt[i])
            if(lab[v[i]]==lab[u]+1 && res[i]>0) {
                tmp = dinicDfs(min(delta, res[i]), v[i], t);
                sum += tmp;
                delta -= tmp;
                res[i] -= tmp;
                res[i^1] += tmp;
                if(delta == 0)  break;
            }
        if(sum == 0)  lab[u] = -1;
        return  sum;
    }
}
int maxFlow(int s, int t) {
    int ans =0;
    while(bfs(s, t))
        ans += dinicDfs(inf, s, t);
    return  ans;
}
int main()
{
    int a, b, c, s, t;
    freopen("data.txt", "r", stdin);
    while(scanf("%d%d", &n, &m) != EOF) {
        s = 0; t = n+1;
        tot = 0;
        for(int i = 0; i <= t; i++)  h[i] = -1;
        for(int i = 1; i <= n; i++) {
            scanf("%d%d", &a, &b);
            addEdge(s, i, a); addEdge(i, t, b);
        }
        while(m--) {
            scanf("%d%d%d", &a, &b, &c);
            addEdge(a, b, c); addEdge(b, a, c);
        }
        int ans = maxFlow(s, t);
        cout << ans << endl;
    }
    return  0;
}
最短路径(spfa判负环)
#include <iostream>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <vector>
#include <queue>
#include <algorithm>
using namespace std;
const int N = 550;
const int M = 3000<<1;
int Case, n, m, w;
int tot, h[N], nxt[M], c[M], v[M];
int used[N], dis[N];
bool visit[N];
void add(int s, int t, int e) {
    v[tot] = t; c[tot] = e;
    nxt[tot] = h[s]; h[s] = tot++;
}
bool spfa(int s) {
    int u;
    queue <int> q; while(!q.empty())  q.pop();
    memset(visit, false, sizeof(visit));
    memset(used, 0, sizeof(used));
    for(int i = 1; i <= n; i++)  dis[i] = 0x1fffffff; dis[0] = 0;
    used[0] = 1;
    q.push(s);
    while(!q.empty()) {
        u = q.front(); q.pop();
        visit[u] = false;
        for(int p = h[u]; p != -1; p = nxt[p]) {
            if(dis[v[p]] > dis[u] + c[p]) {
                dis[v[p]] = dis[u] + c[p];
                if(!visit[v[p]]) {
                    visit[v[p]] = true;
                    q.push(v[p]);
                    used[v[p]]++;
                    if(used[v[p]] >= n)  return  true;
                }
            }
        }
    }
    return  false;
}
int main() {
    int s, t, e;
    scanf("%d", &Case);
    while(Case--) {
        scanf("%d%d%d", &n, &m, &w);
        memset(h, -1, sizeof(h)); tot = 0;
        for(int i = 0; i < m; i++) {
            scanf("%d%d%d", &s, &t, &e);
            add(s, t, e);
            add(t, s, e);
        }
        for(int i = 0; i < w; i++) {
            scanf("%d%d%d", &s, &t, &e);
            add(s, t, -e);
        }
        for(int i = 1; i <= n; i++)  add(0, i, 0);
        if(spfa(0))  printf("YES\n");
        else  printf("NO\n");
    }
    return  0;
}
最小生成树 (kruskal、并查集)
#include <iostream>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <vector>
#include <algorithm>
using namespace std;
const int N = 200010;
struct node {
    int x, y, cost;
}e[N];
int n, m, father[N];
bool cmp(const node &a, const node &b) {
    return  a.cost < b.cost;
}
int getFather(int u) {
    if(father[u] != u)  father[u] = getFather(father[u]);
    return  father[u];
}
int kruskal() {
    int fa, fb, sum = 0;
    for(int i = 0; i < n; i++)  father[i] = i;
    sort(e, e+m, cmp);
    for(int i = 0; i < m; i++) {
        fa = getFather(e[i].x); fb = getFather(e[i].y);
        if(fa == fb)  continue;
        else {
            father[fb] = father[fa];
            sum += e[i].cost;
        }
    }
    return  sum;
}
int main() {
    int tot;
    freopen("data.in", "r", stdin);
    while(scanf("%d%d", &n, &m) != EOF) {
        if(n==0 && m==0)  break;
        tot = 0;
        for(int i = 0; i < m; i++) {
            scanf("%d%d%d", &e[i].x, &e[i].y, &e[i].cost);
            tot += e[i].cost;
        }
        int ans = tot-kruskal();
        printf("%d\n", ans);
    }
    return  0;
}
最小生成树prim
#include <iostream>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <vector>
#include <queue>
#include <algorithm>
using namespace std;
const int N = 105;
int Case, n;
bool visit[N];
double x[N], y[N], dis[N], g[N][N];
double Cal(int a, int b) {
    double tx=x[a]-x[b], ty=y[a]-y[b];
    return  sqrt(tx*tx + ty*ty);
}
double prim() {
    double tot = 0.0, min;
    int v;
    for(int i = 1; i <= n; i++)  dis[i] = g[1][i];
    memset(visit, false, sizeof(visit));
    visit[1] = true;
    for(int k = 1; k < n; k++) {
        min = 1e8;
        for(int i = 1; i <= n; i++) {
            if(!visit[i] && min>dis[i]) {
                min = dis[i];
                v = i;
            }
        }
        visit[v] = true;
        for(int i = 1; i <= n; i++) {
            if(!visit[i] && dis[i]>g[v][i]) {
                dis[i] = g[v][i];
            }
        }
        tot += min;
    }
    return  tot;
}
int main() {
    freopen("data.in", "r", stdin);
    scanf("%d", &Case);
    while(Case--) {
        scanf("%d", &n);
        for(int i = 1; i <= n; i++)  scanf("%lf%lf", &x[i], &y[i]);
        for(int i = 1; i <= n; i++) {
            g[i][i] = 0.0;
            for(int j = i+1; j <= n; j++) {
                g[i][j] = g[j][i] = Cal(i, j);
            }
        }
        double ans = prim();
        printf("%.2f\n", ans);
        if(Case)  printf("\n");
    }
    return  0;
}
stl优先队列的简单用法
#include <iostream>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <vector>
#include <queue>
#include <algorithm>
using namespace std;
struct comp {
    bool operator () (int a, int b) {
        return  a > b;
    }
};
int main() {
    freopen("data.in", "r", stdin);
    priority_queue <int, vector<int>, comp> q;
    q.push(11); q.push(0); q.push(22); q.push(16); q.push(6); q.push(8); q.push(100);
    while(!q.empty()) {
        int x = q.top(); q.pop();
        cout << x << endl;
    }
    return  0;
}
输出:
6
11
22
二分图最大匹配
int n, match[N];
bool visit[N], g[N][N];
bool find(int u) {
    for(int i = 0; i < m; i++) {
        if(g[u][i] && !visit[i]) {
            visit[i] = true;
            if(match[i]==-1 || find(match[i])) {
                match[i] = u;
                return  true;
            }
        }
    }
    return  false;
}
int maxMatch() {
    int ans = 0;
    memset(match, -1, sizeof(match));
    for(int i = 0; i < n; i++) {
        if(find(i))  ans++;
        memset(visit, false, sizeof(visit));
    }
    return  ans;
}
康托展开
#include <iostream>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <vector>
#include <algorithm>
using namespace std;
const int N = 10;
int p[N], fac[N];
int Cal(int p[], int n) {
    int ans = 0;
    for(int i = 0; i < n; i++) {
        int ct = 0;
        for(int j = i+1; j < n; j++) {
            if(p[j] < p[i])  ct++;
        }
        ans += ct*fac[n-i-1];
    }
    return  ans+1;
}
int main() {
    int n;
    fac[0] = 1;
    for(int i = 1; i < N; i ++)  fac[i] = fac[i-1]*i;
    while(cin >> n) {
        for(int i = 0; i < n; i++)  cin >> p[i];
        int ans = Cal(p, n);
        cout << ans << endl;
    }
    return  0;
}
最小费用(最大)流
#include <iostream>
#include <algorithm>
#include <string>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <queue>
#include <vector>
#include <cmath>
using namespace std;
int sumFlow;
const int MAXN = 1010;
const int MAXM = 1000200;
const int INF = 1000000000;
struct Edge
{
    int u, v, cap, cost;
    int next;
}edge[MAXM<<2];
int NE;
int head[MAXN], dist[MAXN], pp[MAXN];
bool vis[MAXN];
void init()
{
    NE = 0;
    memset(head, -1, sizeof(head));
}
void addedge(int u, int v, int cap, int cost)
{
    edge[NE].u = u; edge[NE].v = v; edge[NE].cap = cap; edge[NE].cost = cost;
    edge[NE].next = head[u]; head[u] = NE++;
    edge[NE].u = v; edge[NE].v = u; edge[NE].cap = 0; edge[NE].cost = -cost;
    edge[NE].next = head[v]; head[v] = NE++;
}
bool SPFA(int s, int t, int n)
{
    int i, u, v;
    queue <int> qu;
    memset(vis,false,sizeof(vis));
    memset(pp,-1,sizeof(pp));
    for(i = 0; i <= n; i++) dist[i] = INF;
    vis[s] = true; dist[s] = 0;
    qu.push(s);
    while(!qu.empty())
    {
        u = qu.front(); qu.pop(); vis[u] = false;
        for(i = head[u]; i != -1; i = edge[i].next)
        {
            v = edge[i].v;
            if(edge[i].cap && dist[v] > dist[u] + edge[i].cost)
            {
                dist[v] = dist[u] + edge[i].cost;
                pp[v] = i;
                if(!vis[v])
                {
                    qu.push(v);
                    vis[v] = true;
                }
            }
        }
    }
    if(dist[t] == INF) return false;
    return true;
}
int MCMF(int s, int t, int n) // minCostMaxFlow
{
    int flow = 0; // 总流量
    int i, minflow, mincost;
    mincost = 0;
    while(SPFA(s, t, n))
    {
        minflow = INF + 1;
        for(i = pp[t]; i != -1; i = pp[edge[i].u])
            if(edge[i].cap < minflow)
                minflow = edge[i].cap;
        flow += minflow;
        for(i = pp[t]; i != -1; i = pp[edge[i].u])
        {
            edge[i].cap -= minflow;
            edge[i^1].cap += minflow;
        }
        mincost += dist[t] * minflow;
    }
    sumFlow = flow; // 最大流
    return mincost;
}
日期类
int days[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
class Date {
public:
    //判断是否闰年
    inline static bool isLeap(int year) {
        return (year % 4 == 0 && year % 100 != 0) || year % 400 == 0;
    }
    int year, month, day;
    Date() {}
    Date(int y, int m, int d) : year(y), month(m), day(d) {}
    //判断日期是否合法
    inline bool isLegal() const {
        if (month <= 0 || month > 12) {
            return false;
        }
        if (month == 2) {
            return day > 0 && day <= 28 + isLeap(year);
        }
        return day > 0 && day <= days[month - 1];
    }
    //与另一个日期比较
    inline int compareTo(const Date &other) const {
        if (year != other.year) {
            return year - other.year;
        }
        if (month != other.month) {
            return month - other.month;
        }
        return day - other.day;
    }
    //返回当前日期是星期几 0 (Sunday) ... 6 (Saturday)
    inline int toWeekday() const {
        int tm = month >= 3 ? (month - 2) : (month + 10);
        int ty = month >= 3 ? year : (year - 1);
        return (ty + ty / 4 - ty / 100 + ty / 400 + (int)(2.6 * tm - 0.2) + day) % 7;
    }
    //将日期转换为偏移量
    inline int toInt() const {
        int ret = year * 365 + (year - 1) / 4 - (year - 1) / 100 + (year - 1) / 400;
        days[1] += isLeap(year);
        for (int i = 0; i < month - 1; ret += days[i++]);
        days[1] = 28;
        return ret + day;
    }
    //根据给定的偏移量设置当前日期
    inline void fromInt(int a) {
        year = a / 146097 * 400;
        for (a %= 146097; a >= 365 + isLeap(year); a -= 365 + isLeap(year), year++);
        days[1] += isLeap(year);
        for (month = 1; a >= days[month - 1]; a -= days[month - 1], month++);
        days[1] = 28;
        day = a + 1;
    }
};
不带size域的treap
// 不带size域的treap
class Treap {
public:
    const static int MaxN = 100000;
    int root, tsize, l[MaxN], r[MaxN], p[MaxN];
    int key[MaxN];
    void rot_l(int &x) {    //before using this function, please ensure that the right son of x exist
        int tmp = r[x];
        r[x] = l[tmp]; l[tmp] = x;
        x = tmp;
    }
    void rot_r(int &x) {    //before using this function, please ensure that the left son of x exist
        int tmp = l[x];
        l[x] = r[tmp]; r[tmp] = x;
        x = tmp;
    }
    Treap():root(-1),tsize(-1) {}
    void insert(int &root, const int &x) {
        if(root == -1) {
            key[++tsize] = x;
            root = tsize;
            p[root] = rand();
            l[root] = r[root] = -1;
        }
        else if(x <= key[root]) {
            insert(l[root], x);
            if(p[l[root]] > p[root])  rot_r(root);
        }
        else {
            insert(r[root], x);
            if(p[r[root]] > p[root])  rot_l(root);
        }
    }
    void del(int &root, const int &x) {
        if(key[root] == x) {
            if(l[root]==-1 && r[root]==-1)  root = -1;
            else if(l[root] == -1)  root = r[root];
            else if(r[root] == -1)  root = l[root];
            else {
                if(p[l[root]] > p[r[root]]) {
                    rot_r(root);
                    del(r[root], x);
                }
                else {
                    rot_l(root);
                    del(l[root], x);
                }
            }
        }
        else if(x < key[root])  del(l[root], x);
        else del(r[root], x);
    }
    bool find(int &root, const int &x) {
        if(root == -1)  return  false;
        if(x == key[root])  return  true;
        else if(x < key[root])  return  find(l[root], x);
        else return  find(r[root], x);
    }
};
带size域的treap
//带size的treap
class Treap {
public:
    const static int MaxN = 100000;
    int root, tsize, l[MaxN], r[MaxN], p[MaxN], nsize[MaxN];
    int key[MaxN];
    void maintain(const int &root) {
        int ta, tb;
        ta = l[root]==-1? 0 : nsize[l[root]];
        tb = r[root]==-1? 0 : nsize[r[root]];
        nsize[root] = ta+tb+1;
    }
    void rot_l(int &x) {    //before using this function, please ensure that the right son of x exist
        int tmp = r[x];
        r[x] = l[tmp]; maintain(x);
        l[tmp] = x; x = tmp; maintain(x);
    }
    void rot_r(int &x) {    //before using this function, please ensure that the left son of x exist
        int tmp = l[x];
        l[x] = r[tmp]; maintain(x);
        r[tmp] = x; x = tmp; maintain(x);
    }
    Treap():root(-1),tsize(-1) {}
    void insert(int &root, const int &x) {
        if(root == -1) {
            key[++tsize] = x;
            root = tsize;
            p[root] = rand();
            l[root] = r[root] = -1;
            nsize[root] = 1;
        }
        else if(x <= key[root]) {
            insert(l[root], x);
            if(p[l[root]] > p[root])  rot_r(root);
        }
        else {
            insert(r[root], x);
            if(p[r[root]] > p[root])  rot_l(root);
        }
        maintain(root);
    }
    void del(int &root, const int &x) {
        if(key[root] == x) {
            if(l[root]==-1 && r[root]==-1)  root = -1;
            else if(l[root] == -1)  root = r[root];
            else if(r[root] == -1)  root = l[root];
            else {
                if(p[l[root]] > p[r[root]]) {
                    rot_r(root);
                    del(r[root], x);
                }
                else {
                    rot_l(root);
                    del(l[root], x);
                }
            }
        }
        else if(x < key[root])  del(l[root], x);
        else del(r[root], x);
        if(root != -1)  maintain(root);
    }
    int kthElement(const int &root, int k) {
        int ta;
        ta = l[root]==-1? 0 : nsize[l[root]];
        if(ta >= k)  return  kthElement(l[root], k);
        else if(ta+1 == k)  return  key[root];
        else  return  kthElement(r[root], k-ta-1);
    }
    bool find(int &root, const int &x) {
        if(root == -1)  return  false;
        if(x == key[root])  return  true;
        else if(x < key[root])  return  find(l[root], x);
        else return  find(r[root], x);
    }
};
Splay Top-down实现
class SplayTree
{
public:
    SplayTree();
    int getMaxValure();
    int getMinValure();
    void deleteElement(const int &x);
    void insertElement(const int &x);
    bool findElement(const int &x);
    int preElement(const int &x);
    int succElement(const int &x);
private:
    struct node
    {
        int key;
        node *lchild, *rchild;
        node(){}
        node(const int &x):key(x) {}
    }*root, *nullnode;
    void Zig(node *&x);  //右旋
    void Zag(node *&x);  //左旋
    void splay(node *&root, const int &x);
};
SplayTree::SplayTree()
{
    nullnode = new node();
    nullnode->lchild = nullnode;
    nullnode->rchild = nullnode;
    root = nullnode;
}
int SplayTree::getMaxValure()
{
    node *p = root;
    while(p->rchild != nullnode)  p = p->rchild;
    splay(root, p->key);
    return  p->key;
}
int SplayTree::getMinValure()
{
    node *p = root;
    while(p->lchild != nullnode)  p = p->lchild;
    splay(root, p->key);
    return  p->key;
}
void SplayTree::deleteElement(const int &x)
{
    node *newnode;
    splay(root, x);
    if(root->key != x)  return;
    if(root->lchild == nullnode)
        newnode = root->rchild;
    else
    {
        newnode = root->lchild;
        splay(newnode, x);
        newnode->rchild = root->rchild;
    }
    delete root;
    root = newnode;
}
void SplayTree::insertElement(const int &x)
{
    node *newnode = new node(x);
    if(root == nullnode)
    {
        root = newnode;
        root->lchild = nullnode;
        root->rchild = nullnode;
        return;
    }
    splay(root, x);
    if(x < root->key)
    {
        newnode->lchild = root->lchild;
        root->lchild = nullnode;
        newnode->rchild = root;
        root = newnode;
    }
    else
    {
        newnode->rchild = root->rchild;
        root->rchild = nullnode;
        newnode->lchild = root;
        root = newnode;
    }
}
void SplayTree::Zig(node *&x)
{
    node *y = x->lchild;
    x->lchild = y->rchild;
    y->rchild = x;
    x = y;
}
void SplayTree::Zag(node *&x)
{
    node *y = x->rchild;
    x->rchild = y->lchild;
    y->lchild = x;
    x = y;
}
void SplayTree::splay(node *&root, const int &x)
{
    node headnode;
    node *ltree, *rtree;
    headnode.lchild = headnode.rchild = nullnode;
    ltree = rtree = &headnode;
    while(root->key != x)
    {
        if(x < root->key)
        {
            if(root->lchild!=nullnode && x<root->lchild->key)
                Zig(root);
            if(root->lchild == nullnode)  break;
            rtree->lchild = root;
            rtree = root;
            root = root->lchild;
        }
        else
        {
            if(root->rchild!=nullnode && root->rchild->key<x)
                Zag(root);
            if(root->rchild == nullnode)  break;
            ltree->rchild = root;
            ltree = root;
            root = root->rchild;
        }
    }
    ltree->rchild = root->lchild;
    root->lchild = headnode.rchild;
    rtree->lchild = root->rchild;
    root->rchild = headnode.lchild;
}
bool SplayTree::findElement(const int &x)
{
    splay(root, x);
    if(root->key == x)  return  true;
    else  return  false;
}
int SplayTree::preElement(const int &x)
{
    int ans = 0;
    splay(root, x);
    node *p = root;
    while(p != nullnode)
    {
        if(p->key < x)
        {
            ans = p->key;
            p = p->rchild;
        }
        else  p = p->lchild;
    }
    return  ans;
}
int SplayTree::succElement(const int &x)
{
    int ans = 0x1fffffff;
    splay(root, x);
    node *p = root;
    while(p != nullnode)
    {
        if(p->key > x)
        {
            ans = p->key;
            p = p->lchild;
        }
        else  p = p->rchild;
    }
    return  ans;
}
自适应辛普森公式
#include <cmath>
#include <cstdio>
#include <cstring>
#include <string>
#include <vector>
#include <utility>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long llg;
//本函数在模板中无意义,需根据不同的积分表达式编写
double F(double x) {
    return  x;
}
double simpson(double a, double b) {
    double c = (a+b)/2;
    return  (F(a)+4*F(c)+F(b))*(b-a)/6;
}
double asr(double a, double b, double eps, double A) {
    double c = (a+b)/2;
    double L = simpson(a, c), R = simpson(c, b);
    if(fabs(L+R-A) <= 15*eps)  return  L+R+(L+R-A)/15.0;
    return  asr(a, c, eps/2, L) + asr(c, b, eps/2, R);
}
double asr(double a, double b, double eps) {
    return  asr(a, b, eps, simpson(a, b));
}
int main() {
    freopen("data.in", "r", stdin);
    cout << asr(0, 1, 1e-5) << endl;
    return  0;
}
素数测试和因子分解
#include <iostream>
#include <ctime>
#include <cstdio>
#include <cstdlib>
#include <cstring>
using namespace std;
typedef longlong llg;
const int S =70;
llg tot, p[80];
llg mullg(llg a, llg b, llg n)
{
    llg ans =0, tmp = a%n;
    while(b)
    {
        if(b &1)  ans += tmp;
        if(ans >= n)  ans -= n;
        b >>=1;
        tmp <<=1;
        if(tmp >= n)  tmp -= n;
    }
    return  ans;
}
llg powMod(llg a, llg b, llg n)
{
    llg ans =1, tmp = a % n;
    while(b)
    {
        if(b &1)  ans = mullg(ans, tmp, n);
        b >>=1;
        tmp = mullg(tmp, tmp, n);
    }
    return  ans;
}
bool witness(llg a, llg n)
{
    int i, t =0;
    llg x, tx, nn = n-1;
    while((nn&1) ==0)
    {
        nn >>=1;
        t++;
    }
    x = powMod(a, nn, n);
    for(i =1; i <= t; i++)
    {
        tx = mullg(x, x, n);
        if(tx==1&& x!=1&& x!=n-1)
            return  true;
        x = tx;
    }
    if(x !=1)  return  true;
    return  false;
}
bool millerRabin(llg n)
{
    int i;
    llg a;
    if(n <2)  return  false;
    if(n ==2)  return  true;
    for(i =1; i <= S; i++)
    {
        a = (llg)rand()%(n-1) +1;
        if(witness(a, n))
            return  false;
    }
    return  true;
}
llg Abs(llg x)
{
    if(x <0)  x =-x;
    return  x;
}
llg gcd(llg a, llg b)
{
    if(b ==0)  return  a;
    else return  gcd(b, a%b);
}
llg pollardRho(llg n, int c)
{
    int i =0;
    llg x, y, k, d;
    y = x = rand()%(n-1) +1;
    k =2;
    while(1)
    {
        i++;
        x = (mullg(x, x, n)+c) % n;
        d = gcd(Abs(y-x), n);
        if(d!=1&& d!=n)  return  d;
        if(y == x)  return  n;
        if(i == k)
        {
            y = x;
            k <<=1;
        }
    }
}
void findFac(llg n)
{
    if(millerRabin(n))
    {
        p[tot++] = n;
        return;
    }
    else
    {
        //if(depth > 100)  return;
        llg p = n;
        while(p==n && p)  p = pollardRho(p, rand()%(n-1)+1);
        findFac(p);
        findFac(n/p);
    }
}