[Template]省选复习计划

来源:互联网 发布:c 编程基础视频教程 编辑:程序博客网 时间:2024/05/16 11:18

[Template]省选复习计划


字符串相关

KMP算法(luogu3375)

740′′

#include <bits/stdc++.h>using namespace std;const int MAXN = 1000005, MAXM = 1005;char s1[MAXN], s2[MAXM];int pi[MAXM];void kmp_init(int len){    pi[0] = pi[1] = 0;    int j = 0;    for (int i = 2; i <= len; i++) {        while (j && s2[j+1] != s2[i]) j = pi[j];        if (s2[j+1] == s2[i]) j++;        pi[i] = j;    }}void kmp_match(int len){    int j = 0, p = strlen(s2+1);    for (int i = 1; i <= len; i++) {        while (j && s1[i] != s2[j+1]) j = pi[j];        if (s1[i] == s2[j+1]) ++j;        if (j == p) printf("%d\n", i-p+1), j = pi[j];    }}int main(){    scanf("%s", s1+1), scanf("%s", s2+1);    kmp_init(strlen(s2+1));    kmp_match(strlen(s1+1));    for (int i = 1, l = strlen(s2+1); i <= l; i++)        printf("%d ", pi[i]);    return 0;}

AC自动机(hdu2222)

3242′′

#include <bits/stdc++.h>using namespace std;const int MAXN = 1000005;int chl[MAXN][26], fail[MAXN], fin[MAXN], top = 0, root = 0, mak[MAXN];void push(int &nd, char *str){    if (!nd) nd = ++top;    if (*str == '\0') fin[nd]++;    else push(chl[nd][*str-'a'], str+1);}struct node {    int to, next;} edge[MAXN];int head[MAXN], tp = 0;void push(int i, int j){ ++tp, edge[tp] = (node) {j, head[i]}, head[i] = tp; }queue<int> que;void init(){    fail[root] = 0, que.push(root);    while (!que.empty()) {        int tp = que.front(); que.pop();        for (int i = 0; i < 26; i++) {            if (!chl[tp][i]) continue;            int p = fail[tp];            while (p && !chl[p][i]) p = fail[p];            if (p) fail[chl[tp][i]] = chl[p][i];            else fail[chl[tp][i]] = root;            push(fail[chl[tp][i]], chl[tp][i]);            que.push(chl[tp][i]);        }    }}void match(int nd, char *str){    if (fin[nd]) mak[nd] = 1;    if (*str == '\0') return;    while (nd && !chl[nd][*str-'a']) nd = fail[nd];    if (nd) match(chl[nd][*str-'a'], str+1);    else match(root, str+1);}int dp[MAXN], siz[MAXN]; // 两次collectint dfs1(int nd){    if (!nd) return 0;    if (siz[nd] != -1) return siz[nd];    for (int i = 0; i < 26; i++)        mak[nd] |= dfs1(chl[nd][i]);    return siz[nd] = mak[nd];}int dfs2(int nd){    if (dp[nd] != -1) return dp[nd];    dp[nd] = siz[nd];    for (int i = head[nd]; i; i = edge[i].next) {        int to = edge[i].to;        dp[nd] |= dfs2(to);    }    return dp[nd];}char str[MAXN];int T, n;void clear(){    top = root = tp = 0, memset(chl, 0, sizeof chl), memset(fail, 0, sizeof fail);    memset(fin, 0, sizeof fin), memset(mak, 0, sizeof mak);    memset(siz, -1, sizeof siz), memset(dp, -1, sizeof dp);    memset(head, 0, sizeof head);}int main(){    scanf("%d", &T);    while (T--) {        clear();        scanf("%d", &n);        for (int i = 1; i <= n; i++) {            scanf("%s", str);            push(root, str);        }        init();        scanf("%s", str);        match(root, str);        dfs1(root), dfs2(root);        int ans = 0;        for (int i = 1; i <= top; i++)            ans += dfs2(i)*fin[i];        printf("%d\n", ans);    }    return 0;}

SA

24′′04,然而参考了模板…

第二次1415′′

#include <bits/stdc++.h>using namespace std;const int MAXN = 1e5+5, N = 1e5;struct ele {    int k[2], id;    ele(){}    ele(int a, int b, int c) { k[0] = a, k[1] = b, id = c; }} RE[MAXN], RT[MAXN];int sa[MAXN], rk[MAXN], height[MAXN], sum[MAXN], n;char str[MAXN];void radix_sort(){    for (int y = 1; y >= 0; y--) {        memset(sum, 0, sizeof sum);        for (int i = 1; i <= n; i++) sum[RE[i].k[y]]++;        for (int i = 1; i <= N; i++) sum[i] += sum[i-1];        for (int i = n; i >= 1; i--) RT[sum[RE[i].k[y]]--] = RE[i];        for (int i = 1; i <= n; i++) RE[i] = RT[i];    }    for (int i = 1; i <= n; i++) {        rk[RE[i].id] = rk[RE[i-1].id];        if (RE[i].k[0] != RE[i-1].k[0] || RE[i].k[1] != RE[i-1].k[1])            rk[RE[i].id]++;    }}void calc_sa(){    for (int i = 1; i <= n; i++) RE[i] = ele(str[i]-'a'+1, 0, i);    radix_sort();    for (int k = 1; k < n; k <<= 1) {        for (int i = 1; i <= n; i++) RE[i] = ele(rk[i], i+k<=n?rk[i+k]:0, i);        radix_sort();    }    for (int i = 1; i <= n; i++) sa[rk[i]] = i;}void calc_height(){    int h = 0;    for (int i = 1; i <= n; i++) {        if (rk[i] == 1) h = 0;        else {            int k = sa[rk[i]-1];            if (--h < 0) h = 0;            while (str[i+h] == str[k+h]) h++;        }        height[rk[i]] = h;    }}int main(){    scanf("%s", str+1);    n = strlen(str+1);    calc_sa(), calc_height();    for (int i = 1; i <= n; i++) printf("%d ", sa[i]); puts("");    for (int i = 2; i <= n; i++) printf("%d ", height[i]);    return 0;}

SAM

luogu2852
859′′

#include <bits/stdc++.h>using namespace std;const int MAXN = 40005;map<int, int> chl[MAXN];int fa[MAXN], maxl[MAXN], right_siz[MAXN];int top = 1, root = 1, last = 1;void push(int x){    int p = last, np = ++top; maxl[np] = maxl[p]+1, right_siz[np] = 1;    while (p && !chl[p][x]) chl[p][x] = np, p = fa[p];    if (!p) fa[np] = root;    else {        int q = chl[p][x];        if (maxl[q] == maxl[p] + 1) fa[np] = q;        else {            int nq = ++top; maxl[nq] = maxl[p]+1, chl[nq] = chl[q];            fa[nq] = fa[q], fa[q] = fa[np] = nq;            while (p && chl[p][x] == q) chl[p][x] = nq, p = fa[p];        }    }    last = np;}struct node {    int to, next;} edge[MAXN];int head[MAXN], tp = 0;void push(int i, int j){ ++tp, edge[tp] = (node){j, head[i]}, head[i] = tp; }int n, k, ans = 0;void dfs(int nd){    for (int i = head[nd]; i; i = edge[i].next) {        dfs(edge[i].to);        right_siz[nd] += right_siz[edge[i].to];    }    if (right_siz[nd] >= k) ans = max(ans, maxl[nd]);}int main(){    scanf("%d%d", &n, &k);    for (int i = 1; i <= n; i++) {        int u; scanf("%d", &u);        push(u);    }    for (int i = 2; i <= top; i++) push(fa[i], i);    dfs(root);    cout << ans << endl;    return 0;}

bzoj3238: [Ahoi2013]差异

30。因为longlong WA了一次。
后缀自动机parent树=逆序后缀树,后缀长度=maxl[nd]

#include <bits/stdc++.h>using namespace std;const int MAXN = 500005*2;int chl[MAXN][26], fa[MAXN], maxl[MAXN];long long right_siz[MAXN];int top = 1, root = 1, last = 1;void push(int x){    int p = last, np = ++top; maxl[np] = maxl[p]+1, right_siz[np] = 1;    while (p && !chl[p][x]) chl[p][x] = np, p = fa[p];    if (!p) fa[np] = root;    else {        int q = chl[p][x];        if (maxl[q] == maxl[p] + 1) fa[np] = q;        else {            int nq = ++top; maxl[nq] = maxl[p]+1;            memcpy(chl[nq], chl[q], sizeof chl[q]);            fa[nq] = fa[q], fa[q] = fa[np] = nq;            while (p && chl[p][x] == q) chl[p][x] = nq, p = fa[p];        }    }    last = np;}struct node {    int to, next;} edge[MAXN];int head[MAXN], tp = 0;void push(int i, int j){ edge[++tp] = (node) {j, head[i]}, head[i] = tp; }char str[MAXN];long long dfs(int nd){    long long ans = 0, beg = right_siz[nd];    for (int i = head[nd]; i; i = edge[i].next)        ans += dfs(edge[i].to), right_siz[nd] += right_siz[edge[i].to];    for (int i = head[nd]; i; i = edge[i].next) {        int to = edge[i].to;        ans += right_siz[to]*(right_siz[nd]-right_siz[to])*maxl[nd];    }    ans += beg*(right_siz[nd]-beg)*maxl[nd];    return ans;}void init(){    scanf("%s", str+1);    int n = strlen(str+1);    for (int i = n; i >= 1; i--)        push(str[i]-'a');    for (int i = 2; i <= top; i++) push(fa[i], i);    long long ans = 0;    for (int i = 1; i <= n; i++) ans += (long long)(n-i)*(n-i+1ll)+(long long)(1ll+n-i)*(n-i)/2;    cout << ans-dfs(root) << endl;}int main(){    init();    return 0;}

树相关

树上倍增

NOIP2013 货车运输

#include <bits/stdc++.h>using namespace std;const int MAXN = 10005, MAXM = 100005;struct p {    int x, y, d;    friend bool operator < (const p &a, const p &b)    { return a.d > b.d; }} edge_arr[MAXN];struct node {    int to, next, dis;} edge[MAXN];int head[MAXN], top = 0;void push(int i, int j, int k){ edge[++top] = (node){j, head[i], k}, head[i] = top; }int fa[MAXN];int findf(int nd){ return fa[nd] ? fa[nd] = findf(fa[nd]) : nd; }int n, m;int depth[MAXN], jmp[MAXN][20], min_val[MAXN][20], vis[MAXN];void dfs(int nd, int f){    jmp[nd][0] = f, depth[nd] = depth[f] + 1;    for (int j = head[nd]; j; j = edge[j].next) {        int to = edge[j].to, d = edge[j].dis;        if (to == f) continue;        min_val[to][0] = d;        dfs(to, nd);    }}void init(){    for (int j = 1; j < 20; j++)        for (int i = 1; i <= n; i++) {            jmp[i][j] = jmp[jmp[i][j-1]][j-1];            min_val[i][j] = min(min_val[i][j-1], min_val[jmp[i][j-1]][j-1]);        }}int lca(int a, int b){    if (depth[a] < depth[b]) swap(a, b);    for (int i = 0, d = depth[a]-depth[b]; i < 20; i++)        if ((1<<i)&d)            a = jmp[a][i];    if (a == b) return a;    for (int i = 19; i >= 0; i--)        if (jmp[a][i] != jmp[b][i])            a = jmp[a][i], b = jmp[b][i];    return jmp[a][0];}int query(int a, int b){    int c = lca(a, b);    if (findf(a) != findf(b)) return -1;    int ans = INT_MAX;    for (int i = 0, d = depth[a]-depth[c]; i < 20; i++)        if ((1<<i)&d)            ans = min(ans, min_val[a][i]), a = jmp[a][i];    for (int i = 0, d = depth[b]-depth[c]; i < 20; i++)        if ((1<<i)&d)            ans = min(ans, min_val[b][i]), b = jmp[b][i];    return ans;}int main(){    memset(min_val, 127/3, sizeof min_val);    scanf("%d%d", &n, &m);    for (int i = 1; i <= m; i++)        scanf("%d%d%d", &edge_arr[i].x, &edge_arr[i].y, &edge_arr[i].d);    sort(edge_arr+1, edge_arr+m+1);    for (int i = 1; i <= m; i++) {        int u = edge_arr[i].x, v = edge_arr[i].y, d = edge_arr[i].d;        if (findf(u) != findf(v)) {            fa[findf(u)] = findf(v);            push(u, v, d), push(v, u, d);        }    }    depth[0] = 0;    for (int i = 1; i <= n; i++)        if (fa[i] == 0)            dfs(i, 0);    init();    int q; scanf("%d", &q);    for (int i = 1; i <= q; i++) {        int u, v; scanf("%d%d", &u, &v);        printf("%d\n", query(u, v));    }    return 0;}

树链剖分

luogu模板题
50

#include <bits/stdc++.h>using namespace std;const int MAXN = 100005;int lc[MAXN], rc[MAXN], l[MAXN], r[MAXN], root = 0;long long sum[MAXN], lazy[MAXN], P;int tp = 0;void build_tree(int &nd, int opl, int opr){    nd = ++tp, l[nd] = opl, r[nd] = opr;    sum[nd] = lazy[nd] = 0;    if (opl < opr)        build_tree(lc[nd], opl, (opl+opr)/2), build_tree(rc[nd], (opl+opr)/2+1, opr);}void pdw(int nd){    if (!lazy[nd]) return;    if (lc[nd]) lazy[lc[nd]] += lazy[nd];    if (rc[nd]) lazy[rc[nd]] += lazy[nd];    (sum[nd] += lazy[nd]*(r[nd]-l[nd]+1)) %= P;    lazy[nd] = 0;}void modify(int nd, int opl, int opr, long long dt){    if (opl == l[nd] && opr == r[nd]) (lazy[nd] += dt) %= P;    else {        int mid = (l[nd]+r[nd])/2;        (sum[nd] += (opr-opl+1)*dt) %= P;        if (opr <= mid) modify(lc[nd], opl, opr, dt);        else if (opl >= mid+1) modify(rc[nd], opl, opr, dt);        else modify(lc[nd], opl, mid, dt), modify(rc[nd], mid+1, opr, dt);    }}long long query(int nd, int opl, int opr){    if (nd) pdw(nd);    if (opl == l[nd] && opr == r[nd]) return sum[nd]%P;    else {        int mid = (l[nd]+r[nd])/2;        if (opr <= mid) return query(lc[nd], opl, opr);        else if (opl >= mid+1) return query(rc[nd], opl, opr);        else return (query(lc[nd], opl, mid)+query(rc[nd], mid+1, opr))%P;    }}struct node {    int to, next;} edge[MAXN*2];int head[MAXN], top = 0;void push(int i, int j){ edge[++top] = (node) {j, head[i]}, head[i] = top; }int n, m, rt;int siz[MAXN], id[MAXN], out[MAXN], ind[MAXN], rk[MAXN], depth[MAXN];int id_in_ds = 0;int fa[MAXN][21];void dfs(int nd, int f){    fa[nd][0] = f, siz[nd] = 1, depth[nd] = depth[f] + 1;    for (int i = head[nd]; i; i = edge[i].next) {        int to = edge[i].to;        if (to == f) continue;        dfs(to, nd), siz[nd] += siz[to];    }}void dfs2(int nd, int from){    id[nd] = ++id_in_ds, ind[nd] = from;    modify(root, id[nd], id[nd], rk[nd]);    int hev = 0;    for (int i = head[nd]; i; i = edge[i].next) {        int to = edge[i].to;        if (depth[to] < depth[nd]) continue;        if (siz[to] > siz[hev]) hev = to;    }    if (!hev) { out[nd] = id_in_ds; return; }    dfs2(hev, from);    for (int i = head[nd]; i; i = edge[i].next) {        int to = edge[i].to;        if (depth[to] < depth[nd]) continue;        if (to != hev) dfs2(to, to);    }    out[nd] = id_in_ds;}void init(){    for (int j = 1; j <= 20; j++)        for (int i = 1; i <= n; i++)            fa[i][j] = fa[fa[i][j-1]][j-1];}int lca(int a, int b){    if (depth[a] < depth[b]) swap(a, b);    for (int d = depth[a]-depth[b], i = 0; i <= 20; i++)        if (d&(1<<i))            a = fa[a][i];    if (a == b) return a;    for (int i = 20; i >= 0; i--)        if (fa[a][i] != fa[b][i])            a = fa[a][i], b = fa[b][i];    return fa[a][0];}void add_path(int a, long long dt) // a到根{    while (a) {        modify(root, id[ind[a]], id[a], dt);        a = fa[ind[a]][0];    }}void add_son(int a, int dt){ modify(root, id[a], out[a], dt); }long long query_path(int a) //{    long long ans = 0;    while (a) {        (ans += query(root, id[ind[a]], id[a])) %= P;        a = fa[ind[a]][0];    }    return ans;}long long query_son(int a){ return query(root, id[a], out[a]); }int main(){    scanf("%d%d%d%lld", &n, &m, &rt, &P);    for (int i = 1; i <= n; i++) scanf("%d", &rk[i]);    build_tree(root, 1, n);    for (int i = 1; i < n; i++) {        int u, v; scanf("%d%d", &u, &v);        push(u, v), push(v, u);    }    depth[rt] = 0, dfs(rt, 0);    dfs2(rt, rt);    init();    for (int i = 1; i <= m; i++) {        int tp, x, y;        long long z;        scanf("%d", &tp);        if (tp == 1) {            scanf("%d%d%lld", &x, &y, &z);            int c = lca(x, y);            add_path(x, z), add_path(y, z);            add_path(c, -2*z);            modify(root, id[c], id[c], z);        } else if (tp == 2) {            scanf("%d%d", &x, &y);            int c = lca(x, y);            printf("%lld\n", ((query_path(x)+query_path(y)-2*query_path(c)+query(root, id[c], id[c]))%P+P)%P);        } else if (tp == 3) {            scanf("%d%lld", &x, &z);            add_son(x, z);        } else if (tp == 4) {            scanf("%d", &x);            printf("%lld\n", query_son(x));        } else throw;    }    return 0;}

dfs序

bzoj4034: [HAOI2015]树上操作
这个题其实树剖很好写,不过dfs序的思路太神辣所以必须发…http://www.cnblogs.com/liyinggang/p/5965981.html

pdw写错+10086…
虽然dfs序理论复杂度O(nlgn)但是由于写法太渣跑的还没有链剖快…

#include <bits/stdc++.h>using namespace std;const int MAXN = 100005*8;int n, m;int lc[MAXN], rc[MAXN], l[MAXN], r[MAXN];long long sum[MAXN], lazy[MAXN];long long num[MAXN], num_tmp[MAXN];int root = 0, top_ds = 0;void build(int &nd, int opl, int opr){    nd = ++top_ds, sum[nd] = 0;    l[nd] = opl, r[nd] = opr;    if (opl < opr) {        build(lc[nd], opl, (opl+opr)/2);        build(rc[nd], (opl+opr)/2+1, opr);        num[nd] = num[lc[nd]] + num[rc[nd]];    } else num[nd] = num_tmp[opl];}void pdw(int nd){    if (!lazy[nd]) return;    sum[nd] += num[nd]*lazy[nd];    if (lc[nd]) lazy[lc[nd]] += lazy[nd];    if (rc[nd]) lazy[rc[nd]] += lazy[nd];    lazy[nd] = 0;}void modify(int nd, int opl, int opr, long long dat){    if (opl == l[nd] && opr == r[nd]) lazy[nd] += dat, pdw(nd);    else {        pdw(nd);        int mid = (l[nd]+r[nd])>>1;        if (opr <= mid) modify(lc[nd], opl, opr, dat);        else if (opl >= mid+1) modify(rc[nd], opl, opr, dat);        else modify(lc[nd], opl, mid, dat), modify(rc[nd], mid+1, opr, dat);        pdw(lc[nd]), pdw(rc[nd]);        sum[nd] = sum[lc[nd]] + sum[rc[nd]];    }}void display(int nd, int tab){    if (!nd) return;    for (int i = 1; i <= tab; i++) putchar(' ');    printf("[%d,%d] --> sum = %lld, lazy = %lld, num = %lld\n", l[nd], r[nd], sum[nd], lazy[nd], num[nd]);    display(lc[nd], tab+2);    display(rc[nd], tab+2);}long long query(int nd, int opl, int opr){    pdw(nd);    if (opl == l[nd] && opr == r[nd]) return sum[nd];    else {        int mid = (l[nd]+r[nd])>>1;        if (opr <= mid) return query(lc[nd], opl, opr);        else if (opl >= mid+1) return query(rc[nd], opl, opr);        else return query(lc[nd], opl, mid)+query(rc[nd], mid+1, opr);    }}struct node {    int to, next;} edge[MAXN];int head[MAXN], top = 0;void push(int i, int j){ edge[++top] = (node) {j, head[i]}, head[i] = top; }int in[MAXN], out[MAXN], ds_top = 0;int rk[MAXN];void dfs(int nd, int f){    in[nd] = ++ds_top; num_tmp[in[nd]] = 1;    for (int i = head[nd]; i; i = edge[i].next) {        int to = edge[i].to;        if (to == f) continue;        dfs(to, nd);    }    out[nd] = ++ds_top; num_tmp[out[nd]] = -1;}void modify_point(int nd, long long dt){    modify(root, in[nd], in[nd], dt);    modify(root, out[nd], out[nd], dt);}void modify_tree(int nd, long long dt){ modify(root, in[nd], out[nd], dt); }long long query_path(int nd){ return query(root, in[1], in[nd]); }int main(){    scanf("%d%d", &n, &m);    for (int i = 1; i <= n; i++) scanf("%d", &rk[i]);    for (int i = 1; i < n; i++) {        int u, v; scanf("%d%d", &u, &v);        push(u, v), push(v, u);    }    dfs(1, 0);    build(root, 1, 2*n);    for (int i = 1; i <= n; i++) {        modify_point(i, rk[i]);    }    for (int i = 1; i <= m; i++) {        int tp, a;        long long b;        scanf("%d", &tp);        if (tp == 1) {            scanf("%d%lld", &a, &b);            modify_point(a, b);        } else if (tp == 2) {            scanf("%d%lld", &a, &b);            modify_tree(a, b);        } else {            scanf("%d", &a);            printf("%lld\n", query_path(a));        }    }    return 0;}

lct

bzoj3832 Tree
http://hzwer.com/4422.html

1.5h,脑残原因:zig的时候先修改了p的fa,才判断is_rt(p)…

#include <bits/stdc++.h>using namespace std;const int MAXN = 500005;int chl[MAXN][2], fa[MAXN], dat[MAXN], sum[MAXN], top = 0;int rev[MAXN], stk[MAXN], stop = 0, n, m;bool is_rt(int nd){ return chl[fa[nd]][0] != nd && chl[fa[nd]][1] != nd; }void pdw(int nd){    if (!rev[nd]) return;    int &lc = chl[nd][0], &rc = chl[nd][1];    if (lc) rev[lc] ^= 1;    if (rc) rev[rc] ^= 1;    swap(lc, rc), rev[nd] = 0;}inline void update(int nd){    sum[nd] = dat[nd]^sum[chl[nd][0]]^sum[chl[nd][1]];}void zig(int nd){    int p = fa[nd], g = fa[p];    int tp = chl[p][0] != nd, tg = chl[g][0] != p;    int son = chl[nd][tp^1];    if (!is_rt(p)) chl[g][tg] = nd;    fa[son] = p, fa[p] = nd, fa[nd] = g;    chl[nd][tp^1] = p, chl[p][tp] = son;    update(p), update(nd);}void splay(int nd){    stk[stop = 1] = nd;    for (int i = nd; !is_rt(i); i = fa[i]) stk[++stop] = fa[i];    while (stop) pdw(stk[stop--]);    while (!is_rt(nd)) {        int p = fa[nd], g = fa[p], tp = chl[p][0] != nd, tg = chl[g][0] != p;        if (is_rt(p)) { zig(nd); break; }        else if (tp == tg) zig(p), zig(nd);        else zig(nd), zig(nd);    }}void access(int x){    for (int y = 0; x; x = fa[y = x])        splay(x), chl[x][1] = y, update(x);}void make_rt(int x){    access(x), splay(x);    rev[x] ^= 1;}int find_fa(int x){    access(x), splay(x);    while (chl[x][0]) {        if (x == chl[x][0]) throw;        x = chl[x][0];    }    return x;}void link(int x, int y){    if (find_fa(x) == find_fa(y)) return;    make_rt(x), fa[x] = y;    access(x);}void cut(int x, int y){    if (find_fa(x) != find_fa(y)) return;    make_rt(x);    access(y), splay(y);    if (chl[y][0] == x) chl[y][0] = 0, fa[x] = 0;}int query(int x, int y){    make_rt(x), access(y), splay(y);    if (find_fa(y) != x) return -1;    return sum[y];}void change(int x, int dt){    make_rt(x), splay(x), dat[x] = dt, update(x);}int main(){    scanf("%d%d", &n, &m);    for (int i = 1; i <= n; i++) scanf("%d", &dat[i]), update(i);    for (int i = 1; i <= m; i++) {        int tp, x, y;        scanf("%d%d%d", &tp, &x, &y);        if (tp == 0)            printf("%d\n", query(x, y));        else if (tp == 1)            link(x, y);        else if (tp == 2)            cut(x, y);        else change(x, y);    }    return 0;}

bzoj2843: 极地旅行社

Description

不久之前,Mirko建立了一个旅行社,名叫“极地之梦”。这家旅行社在北极附近购买了N座冰岛,并且提供观光服
务。当地最受欢迎的当然是帝企鹅了,这些小家伙经常成群结队的游走在各个冰岛之间。Mirko的旅行社遭受一次
重大打击,以至于观光游轮已经不划算了。旅行社将在冰岛之间建造大桥,并用观光巴士来运载游客。Mirko希望
开发一个电脑程序来管理这些大桥的建造过程,以免有不可预料的错误发生。这些冰岛从1到N标号。一开始时这些
岛屿没有大桥连接,并且所有岛上的帝企鹅数量都是知道的。每座岛上的企鹅数量虽然会有所改变,但是始终在[0
, 1000]之间。你的程序需要处理以下三种命令:

1.”bridge A B”——在A与B之间建立一座大桥(A与B是不同的岛屿)。由于经费限制,这项命令被接受,当且仅当
A与B不联通。若这项命令被接受,你的程序需要输出”yes”,之
后会建造这座大桥。否则,你的程序需要输出”no”。
2.”penguins A X”——根据可靠消息,岛屿A此时的帝企鹅数量变为X。这项命令只是用来提供信息的,你的程序不
需要回应。
3.”excursion A B”——一个旅行团希望从A出发到B。若A与B连通,你的程序需要输出这个旅行团一路上所能看到的
帝企鹅数量(包括起点A与终点B),若不联通,你的程序需要输出”impossible”。

Input

第一行一个正整数N,表示冰岛的数量。
第二行N个范围[0,1000]的整数,为每座岛屿初始的帝企鹅数量。
第三行一个正整数M,表示命令的数量。接下来M行即命令,为题目描述所示。
1<=N<=30000,1<=M<=100000

1604′′

#include <bits/stdc++.h>using namespace std;const int MAXN = 30005;int chl[MAXN][2], fa[MAXN], rev[MAXN], stk[MAXN], sum[MAXN], dat[MAXN], top = 0;inline bool is_rt(int nd){ return chl[fa[nd]][0] != nd && chl[fa[nd]][1] != nd; }inline void update(int nd){ sum[nd] = sum[chl[nd][0]]+sum[chl[nd][1]]+dat[nd]; }void pdw(int nd){    if (!rev[nd]) return;    int &lc = chl[nd][0], &rc = chl[nd][1];    if (lc) rev[lc] ^= 1;    if (rc) rev[rc] ^= 1;    swap(lc, rc), rev[nd] = 0;}void zig(int nd){    int p = fa[nd], g = fa[p];    int tp = chl[p][0] != nd, tg = chl[g][0] != p, son = chl[nd][tp^1];    if (son) fa[son] = p;    if (!is_rt(p)) chl[g][tg] = nd;    fa[p] = nd, fa[nd] = g;    chl[nd][tp^1] = p, chl[p][tp] = son;    update(p), update(nd);}void splay(int nd){    stk[top = 1] = nd;    for (int i = nd; !is_rt(i); i = fa[i]) stk[++top] = fa[i];    while (top) pdw(stk[top--]);    while (!is_rt(nd)) {        int p = fa[nd], g = fa[p];        int tp = chl[p][0] != nd, tg = chl[g][0] != p;        if (is_rt(p)) {zig(nd); break; }        else if (tp == tg) zig(p), zig(nd);        else zig(nd), zig(nd);    }}void access(int x){    for (int y = 0; x; x = fa[y = x])        splay(x), chl[x][1] = y, update(x);}void make_rt(int x){ access(x), splay(x), rev[x] ^= 1; }int find(int x){    access(x), splay(x);    while (chl[x][0]) x = chl[x][0];    return x;}void link(int x, int y){    if (find(x) == find(y)) return;    make_rt(x), access(x), splay(x);    fa[x] = y;}void change(int x, int dt){ make_rt(x), splay(x), dat[x] = dt, update(x); }int query(int x, int y){ return make_rt(x), access(y), splay(y), sum[y]; }int n, m;char str[20];int main(){    scanf("%d", &n);    for (int i = 1; i <= n; i++) scanf("%d",&dat[i]), update(i);    scanf("%d", &m);    for (int i = 1; i <= m; i++) {        int x, y;        scanf("%s %d %d", str, &x, &y);        if (str[0] == 'e') {            if (find(x) != find(y)) puts("impossible");            else printf("%d\n", query(x, y));        } else if (str[0] == 'p') {            change(x, y);        } else if (str[0] == 'b') {            if (find(x) == find(y)) puts("no");            else                puts("yes"), link(x, y);        }    }    return 0;}

数据结构

splay

bzoj1269: [AHOI2006]文本编辑器editor
被pdw支配的恐惧…
几个小操作的先后顺序一定要小心小心再小心啊…这次由于先检查siz后pushdown导致1h+调试…
2h

#include <bits/stdc++.h>using namespace std;const int MAXN = 1024*1024*4;int chl[MAXN][2], fa[MAXN], dat[MAXN], siz[MAXN], rev[MAXN];int top = 0, root = 0;inline void update(int nd){ if(!nd) return; siz[nd] = siz[chl[nd][0]]+siz[chl[nd][1]]+1; }int stk[MAXN], skp = 0;void pdw(int nd){    if (!rev[nd]) return;    int &lc = chl[nd][0], &rc = chl[nd][1];    rev[lc] ^= (lc != 0), rev[rc] ^= (rc != 0);    swap(lc, rc), rev[nd] = 0;}void zig(int nd){    pdw(nd);    int p = fa[nd], g = fa[p];    int tp = chl[p][0] != nd, tg = chl[g][0] != p, son = chl[nd][tp^1];    if (g) chl[g][tg] = nd; else root = nd;    if (son) fa[son] = p;    chl[nd][tp^1] = p, chl[p][tp] = son;    fa[p] = nd, fa[nd] = g;    update(p), update(nd);}void splay(int nd, int tar = 0){    stk[skp = 1] = nd;    for (int i = nd; fa[i]; i = fa[i]) stk[++skp] = fa[i];    while (skp) pdw(stk[skp--]);    while (fa[nd] != tar) {        int p = fa[nd], g = fa[p];        int tp = chl[p][0] != nd, tg = chl[g][0] != p;        if (g == tar) {zig(nd); break; }        else if (tp == tg) zig(p), zig(nd);        else zig(nd), zig(nd);    }}void dfs(int nd, int key){    if (!nd) return;    // pdw(nd);    // for (int i = 1; i <= tab; i++) putchar(' ');    printf("nd = %d, lc = %d, rc = %d, dat = %c, fa = %d-- siz = %d, rev = %d\n", nd, chl[nd][0], chl[nd][1], dat[nd], fa[nd], siz[nd], rev[nd]);    dfs(chl[nd][0], key);    // putchar(dat[nd]); if (key == nd) putchar('|');    dfs(chl[nd][1], key);}int kth(int k){    int nd = root;    while (pdw(nd), siz[chl[nd][0]] != k) {        nd = siz[chl[nd][0]] > k ? chl[nd][0] : (k -= siz[chl[nd][0]]+1, chl[nd][1]);    }    return nd;}int rk(int nd){    splay(nd);    return siz[chl[nd][0]];}int go_prev(int nd){ return kth(rk(nd)-1); }int go_next(int nd){ return kth(rk(nd)+1); }void print(int nd){ putchar(dat[go_next(nd)]); puts(""); }int insert(int nd, int x){    int nx = go_next(nd);    splay(nd);    splay(nx, root);    pdw(root), pdw(nx);    chl[nx][0] = ++top, fa[top] = nx, dat[top] = x, update(top), update(nx), update(nd);    return top;}void del(int nd, int len){    int l = nd, r = kth(rk(nd)+len+1);    splay(l), splay(r, root);    pdw(l), pdw(r);    chl[r][0] = 0, update(r), update(l);}int reverse(int nd, int len){    int l = nd, r = kth(rk(nd)+len+1), k = rk(nd);    splay(l), splay(r, root);    pdw(l), pdw(r);    rev[chl[r][0]] ^= 1;    return kth(k);}int n, k;char str[20], s[MAXN];void get_str(char str[]){    int k = -1, c;    do c = getchar(); while(c < 32 || c > 126);    while (c >= 32 && c <= 126) {        str[++k] = c;        c = getchar();    }    str[++k] = '\0';}int main(){    root = ++top, dat[top] = 0, chl[root][1] = ++top, dat[top] = 1;    fa[top] = top-1;    update(top), update(top-1);    scanf("%d", &n);    int nd = top-1;    for (int i = 1; i <= n; i++) {        scanf("%s", str);        switch(str[0]) {            case 'M': scanf("%d", &k); nd = kth(k); break;            case 'I':                scanf("%d", &k);                get_str(s);                for (int i = 0, x = nd; i < k; i++)                    x = insert(x, s[i]);            break;            case 'D': scanf("%d", &k), del(nd, k); break;            case 'R': scanf("%d", &k), nd = reverse(nd, k); break;            case 'G': print(nd); break;            case 'P': nd = go_prev(nd); break;            case 'N': nd = go_next(nd); break;        }    }    return 0;}

线段树

主席树

无修改区间k大。

#include <bits/stdc++.h>using namespace std;const int MAXN = 100005, lgn = 21;int lc[MAXN*lgn], rc[MAXN*lgn], l[MAXN*lgn], r[MAXN*lgn], sum[MAXN*lgn];int root[MAXN], top = 0;int n, m;void build(int &nd, int opl, int opr){    nd = ++top;    l[nd] = opl, r[nd] = opr, sum[nd] = 0;    if (opl < opr)         build(lc[nd], opl, (opl+opr)/2), build(rc[nd], (opl+opr)/2+1, opr);}void push(int prev, int &nd, int pos){    nd = ++top;    l[nd] = l[prev], r[nd] = r[prev];    if (l[prev] == r[prev]) sum[nd] = sum[prev]+1;    else {        int mid = (l[prev]+r[prev])/2;        if (pos <= mid) push(lc[prev], lc[nd], pos), rc[nd] = rc[prev];        else push(rc[prev], rc[nd], pos), lc[nd] = lc[prev];        sum[nd] = sum[lc[nd]]+sum[rc[nd]];    }}void dfs(int nd, int tab = 0){    if (!nd) return;    for (int i = 1; i <= tab; i++) putchar(' ');        printf("[%d,%d] -- sum = %d\n", l[nd], r[nd], sum[nd]);    dfs(lc[nd], tab+2), dfs(rc[nd], tab+2);}int query(int opl, int opr, int k){    int i = 1, j = n, mid;    int a = root[opl-1], b = root[opr];    k--;    while (i < j) {        mid = (i+j)>>1;        if (sum[lc[b]]-sum[lc[a]] <= k) k -= sum[lc[b]]-sum[lc[a]], i = mid+1, a = rc[a], b = rc[b];        else j = mid, a = lc[a], b = lc[b];    }    return i;}int d[MAXN];int dx[MAXN];void dx_init(){    memcpy(dx, d, sizeof d);    sort(dx+1, dx+n+1);}int dx_num(int nd){ return lower_bound(dx+1, dx+n+1, nd)-dx; }int main(){    scanf("%d%d", &n, &m);    build(root[0], 1, n);    for (int i = 1; i <= n; i++)         scanf("%d", &d[i]);    dx_init();    for (int i = 1; i <= n; i++) {        push(root[i-1], root[i], dx_num(d[i]));    }    for (int i = 1; i <= m; i++) {        int u, v, k;        scanf("%d%d%d", &u, &v, &k);        cout << dx[query(u, v, k)] << endl;     }    return 0;}

其他

FFT

大爷题解:http://www.cnblogs.com/iiyiyi/p/5717520.html

好像把一道好题变成练模板了..之后补分析吧..

#include <bits/stdc++.h>using namespace std;const int MAXN = 300005;int rev[MAXN], n;typedef complex<double> Complex;Complex A[MAXN];const double PI = acos(-1);void fft(Complex a[], int n, int flag){    int lgn = int(log2(n)+0.01);    rev[0] = 0;    for (int i = 1; i < n; i++) rev[i] = (rev[i>>1]>>1)|((1<<(lgn-1))*(i&1));    for (int i = 0; i < n; i++) A[i] = a[rev[i]];    for (int k = 2; k <= n; k <<= 1) {        Complex dw = Complex(cos(2*PI/k), flag*sin(2*PI/k));        for (int i = 0; i < n; i += k) {            Complex w = Complex(1, 0), u, v;            for (int j = 0; j < (k>>1); j++) {                u = A[i+j], v = w*A[i+j+(k>>1)];                A[i+j] = u+v, A[i+j+(k>>1)] = u-v;                w *= dw;            }        }    }    for (int i = 0; i < n; i++)        a[i] = A[i]/(flag==1?Complex(1,0):Complex(n,0));}long long k[MAXN];int dat[MAXN];Complex a[MAXN], b[MAXN], c[MAXN];int main(){    scanf("%d", &n);    int N = 1, mx = 0;    for (int i = 0; i < n; i++) {        int t; scanf("%d", &t); dat[i] = t;        mx = max(mx, t);        a[t] += Complex(1, 0);        b[2*t] += Complex(1, 0);        c[3*t] += Complex(1, 0);    }    while (N <= mx*3) N<<=1;    fft(a, N, 1), fft(b, N, 1), fft(c, N, 1);    for (int i = 0; i < N; i++)        a[i]=(a[i]*a[i]*a[i]-Complex(3, 0)*a[i]*b[i]+Complex(2, 0)*c[i])/Complex(6, 0)+(a[i]*a[i]-b[i])/Complex(2, 0)+a[i];    fft(a, N, -1);    for (int i = 0; i < N; i++) {        k[i] += (long long)(a[i].real()+0.1);    }    for (int i = 0; i < N; i++)        if (k[i])            printf("%d %lld\n", i, k[i]);    return 0;}

Tarjan

bzoj2140 稳定婚姻

#include <bits/stdc++.h>using namespace std;const int MAXN = 10005, MAXM = 100005;struct node {    int to, next;} edge[MAXM];int head[MAXN], top = 0;void push(int i, int j){ edge[++top] = (node){j, head[i]}, head[i] = top; }int dfn[MAXN], low[MAXN], stk[MAXN], instk[MAXN], stop = 0, dfs_top = 0;int gp[MAXN], gp_top = 0;int n, m, strtop = 0;map<string, int> tab;string str[MAXN];string s1, s2;void tarjan(int nd){    stk[++stop] = nd, instk[nd] = 1, dfn[nd] = low[nd] = ++dfs_top;    for (int i = head[nd]; i; i = edge[i].next) {        int to = edge[i].to;        if (!dfn[to]) tarjan(to), low[nd] = min(low[nd], low[to]);        else if (instk[to]) low[nd] = min(low[nd], dfn[to]);    }    if (dfn[nd] == low[nd]) {        int now = 0; gp_top++;        // printf(" -- Group %d --\n", gp_top);        do {            now = stk[stop--];            gp[now] = gp_top;            instk[now] = 0;            // cerr << str[now] << " ";        } while (now != nd);        // puts("");    }}int cpx[MAXN], cpy[MAXN];int main(){    scanf("%d", &n);    for (int i = 1; i <= n; i++) {        cin >> s1 >> s2;        if (!tab.count(s1)) tab[s1] = ++strtop, str[strtop] = s1;        if (!tab.count(s2)) tab[s2] = ++strtop, str[strtop] = s2;        push(tab[s2], tab[s1]);        cpx[i] = tab[s1], cpy[i] = tab[s2];    }    scanf("%d", &m);    for (int i = 1; i <= m; i++) {        cin >> s1 >> s2;        push(tab[s1], tab[s2]);    }    for (int i = 1; i <= strtop; i++)        if (!dfn[i])            tarjan(i);    for (int i = 1; i <= n; i++)        if (gp[cpx[i]] == gp[cpy[i]])            puts("Unsafe");        else            puts("Safe");    return 0;}

dinic

CQOI2015 网络吞吐量

spfa居然写跪了…没救了这

#include <bits/stdc++.h>using namespace std;const int MAXN = 2005, MAXM = 200005;struct node {    int to, next;    long long flow;    int neg;} edge[MAXM];int head[MAXN], top = 0;void push(int i, int j, long long f){    ++top, edge[top] = (node){j, head[i], f, top+1}, head[i] = top;    ++top, edge[top] = (node){i, head[j], 0, top-1}, head[j] = top;}const long long inf = 23333333333333ll;int S, T, n, m;int lev[MAXN], vis[MAXN], bfstime = 0;queue<int> que;bool bfs(){    que.push(S), lev[S] = 0, vis[S] = ++bfstime;    while (!que.empty()) {        int t = que.front(); que.pop();        for (int i = head[t]; i; i = edge[i].next) {            int to = edge[i].to;            long long d = edge[i].flow;            if (!d || vis[to] == bfstime) continue;            vis[to] = bfstime, que.push(to), lev[to] = lev[t]+1;        }    }    return vis[T] == bfstime;}long long dfs(int nd, long long flow = inf){    if (!flow || nd == T) return flow;    long long t, ans = 0;    for (int i = head[nd]; i; i = edge[i].next) {        int to = edge[i].to;        long long d = edge[i].flow;        if (!d || lev[to] != lev[nd]+1) continue;        t = dfs(to, min(flow, d));        ans += t, flow -= t;        edge[i].flow -= t, edge[edge[i].neg].flow += t;    }    if (flow) lev[nd] = -1;    return ans;}long long dinic(){    long long ans = 0;    while (bfs()) ans += dfs(S);    return ans;}long long dis[MAXN];int inq[MAXN];long long rk[MAXN];node g2[MAXM];int h2[MAXN], tp = 0;void push2(int i, int j, long long k){ ++tp, g2[tp] = (node){j, h2[i], k, 0}, h2[i] = tp; }void spfa(){    memset(dis, 127/3, sizeof dis);    memset(inq, 0, sizeof inq);    dis[S] = 0, que.push(S), inq[S] = 1;    while (!que.empty()) {        int t = que.front(); que.pop(), inq[t] = 0;        for (int i = h2[t]; i; i = g2[i].next) {            int to = g2[i].to, d = g2[i].flow;            if (dis[to] > dis[t] + d) {                dis[to] = dis[t] + d;                if (!inq[to])                    inq[to] = 1, que.push(to);            }        }    }}int main(){    scanf("%d%d", &n, &m), S = 1, T = n+n;    for (int i = 1; i <= m; i++) {        int u, v;        long long d; scanf("%d%d%lld", &u, &v, &d);        push2(u, v, d), push2(v, u, d);    }    for (int i = 1; i <= n; i++) scanf("%lld", &rk[i]);    spfa();    for (int i = 1; i <= n; i++)        for (int j = h2[i]; j; j = g2[j].next) {            int to = g2[j].to;            long long d = g2[j].flow;            if (dis[to] == dis[i] + d) {                push(i+n, to, inf);                // cout << i << "--" << d << "->" << to << endl;            }        }    push(1, n+1, inf), push(n, n+n, inf);    for (int i = 2; i < n; i++) push(i, i+n, rk[i]);    cout << dinic() << endl;    return 0;}

spfa费用流

[Noi2008]志愿者招募

#include <bits/stdc++.h>using namespace std;const int MAXN = 2005, MAXM = 100005;struct node {    int to, next;    long long flow, cost;    int neg;} edge[MAXM];int head[MAXN], top = 0, S = 2000, T = 2001;long long inf = 23333333333333ll;void push(int i, int j, long long f, long long c){    ++top, edge[top] = (node){j, head[i], f, c, top+1}, head[i] = top;    ++top, edge[top] = (node){i, head[j], 0, -c, top-1}, head[j] = top;}void push_lim(int i, int j, long long mf){    push(S, j, mf, 0), push(i, T, mf, 0);    push(i, j, inf, 0);}long long dis[MAXN];int vis[MAXN], pre[MAXN], pre_edge[MAXN], n, m;queue<int> que;bool spfa(long long &cost){    memset(dis, 127/3, sizeof dis);    memset(vis, 0, sizeof vis);    memset(pre, 0, sizeof pre);    memset(pre_edge, 0, sizeof pre_edge);    vis[S] = 1, dis[S] = 0, que.push(S);    while (!que.empty()) {        int t = que.front(); que.pop(); vis[t] = 0;        for (int i = head[t]; i; i = edge[i].next) {            int to = edge[i].to, c = edge[i].cost;            if (!edge[i].flow) continue;            if (dis[to] > dis[t] + c) {                dis[to] = dis[t] + c;                pre[to] = t, pre_edge[to] = i;                if (!vis[to])                    vis[to] = 1, que.push(to);            }        }    }    if (dis[T] >= inf) return 0;    long long mf = inf;    for (int i = T; i != S; i = pre[i]) mf = min(mf, edge[pre_edge[i]].flow);    for (int i = T; i != S; i = pre[i]) edge[pre_edge[i]].flow -= mf, edge[edge[pre_edge[i]].neg].flow += mf;    cost += dis[T]*mf;    return 1;}long long mcf(){    long long ans = 0;    while (spfa(ans));    return ans;}int main(){    scanf("%d%d", &n, &m);    for (int i = 1; i <= n; i++) {        long long u; scanf("%lld", &u);        push_lim(i, i+1, u);    }    for (int i = 1; i <= m; i++) {        int l, r; long long cost;        scanf("%d%d%lld", &l, &r, &cost);        push(r+1, l, inf, cost);    }    cout << mcf() << endl;    return 0;}
0 0