存一些东西

@

头文件

#pragma comment(linker, "/STACK:102400000,102400000")
//#include<bits/stdc++.h>
#include <ctime>
#include <iostream>
#include <assert.h>
#include <vector>
#include <queue>
#include <cstdio>
#include <algorithm>
#include <cstring>
#define fi first
#define se second
#define endl '
'
#define o2(x) (x)*(x)
#define BASE_MAX 31
#define mk make_pair
#define eb push_back
#define SZ(x) ((int)(x).size())
#define all(x) (x).begin(), (x).end()
#define clr(a, b) memset((a),(b),sizeof((a)))
#define iis std::ios::sync_with_stdio(false); cin.tie(0)
#define my_unique(x) sort(all(x)),x.erase(unique(all(x)),x.end())
using namespace std;
#pragma optimize("-O3")
typedef long long LL;
typedef unsigned long long uLL;
typedef pair<int, int> pii;
inline LL read() {
    LL x = 0;int f = 0;
    char ch = getchar();
    while (ch < '0' || ch > '9') f |= (ch == '-'), ch = getchar();
    while (ch >= '0' && ch <= '9') x = (x << 3) + (x << 1) + ch - '0', ch = getchar();
    return x = f ? -x : x;
}
inline void write(LL x, bool f) {
    if (x == 0) {putchar('0'); if(f)putchar('
');else putchar(' ');return;}
    if (x < 0) {putchar('-');x = -x;}
    static char s[23];
    int l = 0;
    while (x != 0)s[l++] = x % 10 + 48, x /= 10;
    while (l)putchar(s[--l]);
    if(f)putchar('
');else putchar(' ');
}
int lowbit(int x) { return x & (-x); }
template<class T>T big(const T &a1, const T &a2) { return a1 > a2 ? a1 : a2; }
template<class T>T sml(const T &a1, const T &a2) { return a1 < a2 ? a1 : a2; }
template<typename T, typename ...R>T big(const T &f, const R &...r) { return big(f, big(r...)); }
template<typename T, typename ...R>T sml(const T &f, const R &...r) { return sml(f, sml(r...)); }
void debug_out() { cerr << '
'; }
template<typename T, typename ...R>void debug_out(const T &f, const R &...r) {cerr << f << " ";debug_out(r...);}
#define debug(...) cerr << "[" << #__VA_ARGS__ << "]: ", debug_out(__VA_ARGS__);


const LL INFLL = 0x3f3f3f3f3f3f3f3fLL;
const int HMOD[] = {1000000009, 1004535809};
const LL BASE[] = {1572872831, 1971536491};
const int mod = 1e7 + 7;
const int MOD = 1e7 + 7;//998244353
const int INF = 0x3f3f3f3f;

#ifndef ONLINE_JUDGE
    freopen("/home/cwolf9/CLionProjects/ccc/in.txt", "r", stdin);
    //freopen("/home/cwolf9/CLionProjects/ccc/out.txt", "w", stdout);
#endif

线性基

线性基交:牛客2019多校第四场B题

struct Base {
    int b[BASE_MAX + 1];
    int& operator [](int x) {
        return b[x];
    }
    int operator [](int x)const {
        return b[x];
    }
    void clear(int f) {
        if(f == 0) memset(b, 0, sizeof(int)*(BASE_MAX+1));
        else {
            for(int i = 0; i <= BASE_MAX; ++i) b[i] = (1<<i);
        }
    }
    bool check(int x) {
        for(int i = BASE_MAX; i >= 0; --i) {
            if(x & (1 << i)) x ^= b[i];
        }
        return (x == 0);
    }
    void out() {
        for(int i = 0; i <= BASE_MAX; ++i) printf("%d ", b[i]);
        printf("
");
    }
}bs[MXN];
bool insert(int x, int *bs) {
    for(int j = BASE_MAX; j >= 0; --j) {
        if(!(x >> j)) continue;
        if(bs[j]) x ^= bs[j];
        else {
            bs[j] = x;
            for(int k = j-1; k >= 0; --k) if(bs[k]&&(bs[j]&(1LL<<k))) bs[j]^=bs[k];
            for(int k = j+1; k <= BASE_MAX; ++k) if(bs[k]&(1LL<<j)) bs[k]^=bs[j];
            return true;
        }
    }
    return false;
}
Base merge(const Base&a, const Base&b) {//600ms
    Base c = b, d = b, rt = {};
    for(int i = 0; i <= BASE_MAX; ++i) assert(rt[i] == 0);
    for (int i = 0, x; i <= BASE_MAX; ++i) {
        x = a[i];
        if (!x)continue;
        int j = i, T = 0;
        for (; j >= 0; --j) {
            if ((x >> j) & 1)
                if (c[j]) { x ^= c[j]; T ^= d[j]; }
                else break;
        }
        if (!x) rt[i] = T;
        else { c[j] = x; d[j] = T; }
    }
    return rt;
}
Base merge1(const Base&a, const Base&b) {//400ms
    int cur, d;
    Base tot = a, na = a, rt = {};
    for(int i = 0; i <= BASE_MAX; ++i) assert(rt[i] == 0);
    for(int i = 0; i <= BASE_MAX; ++i) if(b[i]) {
            cur = 0, d = b[i];
            for(int j = i; j >= 0; --j) if(d >> j & 1) {
                    if(tot[j]) {
                        d ^= tot[j], cur ^= na[j];
                        if(d == 0) { rt[i] = cur; break; }
                    } else {
                        tot[j] = d;
                        na[j] = cur;
                        break;
                    }
                }
        }
    return rt;
}

单调栈/单调队列相关

  • 单调栈就是用一个栈实现的,可以求左/右边第一个大于/小于他的数字。(笛卡尔树是单调栈升级版)
  • 单调队列用一个双端队列实现,可以头指针和尾指针同时右移。可以保证这个区间内最大/小值位于左端点。
  • 单调栈:我是新来的,都得让着我
  • 单调队列:事已至此,不得不心狠手辣
    2019牛客第三场F题
//类似与求区间最大最小值差小于等于q的区间数量
void solve(int len) {
//    clr(dq1, 0), clr(dq2, 0);
    head1 = tail1 = head2 = tail2 = 0;
    int tmp = 0;
    for(int i = 1; i <= n; ++i) {
        while(head1 < tail1 && Max[i] > Max[dq1[tail1]]) -- tail1;
        while(head2 < tail2 && Min[i] < Min[dq2[tail2]]) -- tail2;
        dq1[++tail1] = i, dq2[++tail2] = i;
//        debug(head1, tail1, head1, tail2)
        while(head1 < tail1 && head2 < tail2 && Max[dq1[head1 + 1]] - Min[dq2[head2 + 1]] > q) {
            if(dq1[head1+1] < dq2[head2+1]) tmp = dq1[++head1];
            else tmp = dq2[++head2];
        }
        ans = big(ans, (i - tmp) * len);
//        debug(len, tmp, i)
    }
}

树分治

点分治

裸题:poj1741
分治的复杂度是较为稳定的(O(nlog(n)))
静态点分治还是比较简单吧,按重心分治,每次能让子树大小减少一半以上,所以分治层数至多(log(n))层,这也是他复杂度稳定的一个原因吧。
每递归一层都要重新求一次该子树的重心,因为每次把重新标记为1了,所以各子树间也不会互相有影响。
后面动态点分治也是在此基础上建立的,感觉动态点分治利用了把重心连成一棵高度均衡(log(n))层的树(点分树?),然后使得一些复杂度看似不太对的暴力,成为了可行解。
复杂度:(O(nlog(n)^2))

const int MXN = 2e4 + 7;
const int MXE = 4e4 + 7;
int n, m;
int tn;
struct lp{
    int v, nex;
    int w;
}cw[MXE];
int tot, head[MXN], dep[MXN], siz[MXN], hvy, hvysiz, vis[MXN];
int stak[MXN];
LL ans;
void add_edge(int a, int b, int c) {
    cw[++ tot].v = b, cw[tot].nex = head[a], cw[tot].w = c;
    head[a] = tot;
    cw[++ tot].v = a, cw[tot].nex = head[b], cw[tot].w = c;
    head[b] = tot;
}
void dfs_pre(int u, int ba) {
    int mm = 0;
    siz[u] = 1;
    for(int i = head[u], v; ~i; i = cw[i].nex) {
        v = cw[i].v;
        if(v == ba || vis[v]) continue;
        dfs_pre(v, u);
        siz[u] += siz[v];
        mm = big(mm, siz[v]);
    }
    mm = big(mm, tn - siz[u]);
    if(hvy == -1 || (mm < hvysiz)) {
        hvy = u;
        hvysiz = mm;
    }
}
void get_dep(int u, int ba) {
    stak[++ stak[0]] = dep[u];
    for(int i = head[u], v; ~i; i = cw[i].nex) {
        v = cw[i].v;
        if(v == ba || vis[v]) continue;
        dep[v] = dep[u] + cw[i].w;
        get_dep(v, u);
    }
}
void get_ans(int u, int w, int flag) {
    stak[0] = 0;
    dep[u] = w;
    get_dep(u, u);
    sort(stak + 1, stak + 1 + stak[0]);
    for(int i = 1, j = stak[0]; i <= stak[0]; ++i) {
        while(j > i && stak[i] + stak[j] > m) -- j;
        ans += flag * big(0, j - i);
    }
//    printf("%d :
", u);
//    for(int i = 1; i <= stak[0]; ++i) printf("%d ", stak[i]);
//    printf("
");
}
void dfs_dian(int u, int ba) {
    vis[u] = 1;
    get_ans(u, 0, 1);
//    printf("%d %lld
", u, ans);
    for(int i = head[u], v; ~i; i = cw[i].nex) {
        v = cw[i].v;
        if(v == ba || vis[v]) continue;
        get_ans(v, cw[i].w, -1);
        tn = siz[v];
        hvy = hvysiz = -1;
        dfs_pre(v, u);
        dfs_dian(hvy ,0);
    }
}
int main() {
    while(~scanf("%d%d", &n, &m) && (n + m)) {
        for(int i = 1; i <= n; ++i) head[i] = -1, vis[i] = 0;
        tot = -1;
        for(int i = 1, a, b, c; i < n; ++i) {
            scanf("%d%d%d", &a, &b, &c);
            add_edge(a, b, c);
        }
        ans = 0;
        tn = n;
        hvy = hvysiz = -1;
        dfs_pre(1, 0);
        dfs_dian(hvy, 0);
        printf("%lld
", ans);
    }
    return 0;
}

边分治

裸题:poj1741
普通的边分治复杂度极不稳定,参考菊花图。边分治复杂度主要决定因素是点的度数。
解决方法是在不影响求解答案的前提下,重构图。让每个点度数至多为(3),又因为你至多会增加(n)个点,所以重构图之后边分治复杂度也是比较稳定的,可能常数会比较大吧。
边分治重建树时有两种重建的方法,一种是构建成类线段树结构(高度均衡),一种是每出现两个点就新建一个点。
法1用vector写比较方便,法2可以不用vector实现(法2有个优化就是让原节点连接一个虚节点和原儿子节点,而不是直接连接一个虚节点)。
老年poj上面法1:500ms,法2:300ms。点分治:200ms。
感觉我边分治写法常数应该巨大无比才对啊,为啥还能不到300ms的。。
复杂度:(O(nlog(n)^2))

//类线段树重建图 500ms
const int MXN = 3e4 + 7;
const int MXE = 6e4 + 7;
int n, m;
int tn;
struct lp{
    int v, nex;
    int w, u;
}cw[MXE];
int tot, head[MXN], siz[MXN], hvy, hvysiz, vis[MXE];
int stkl[MXN], stkr[MXN], suml[MXN], sumr[MXN], id[MXN], sdl[MXN], sdr[MXN], sum[MXN];
vector<pii > vs[MXN];
LL ans;
void add_edge(int a, int b, int c) {
    cw[++ tot].v = b, cw[tot].nex = head[a], cw[tot].w = c, cw[tot].u = a;
    head[a] = tot;
    cw[++ tot].v = a, cw[tot].nex = head[b], cw[tot].w = c, cw[tot].u = b;
    head[b] = tot;
}
void dfs_pre(int u, int ba, int _tn) {
    siz[u] = 1;
    for(int i = head[u], v; ~i; i = cw[i].nex) {
        v = cw[i].v;
        if(v == ba || vis[i] || vis[i^1]) continue;
        dfs_pre(v, u, _tn);
        siz[u] += siz[v];
        if(hvy == -1 || big(hvysiz, _tn - hvysiz) > big(siz[v], _tn - siz[v])) {
            hvy = i;
            hvysiz = siz[v];
        }
    }
}
void dfs_dep(int f, int u, int ba, int w) {
    if(f) stkl[++stkl[0]] = w, suml[stkl[0]] = id[u];
    else stkr[++stkr[0]] = w, sumr[stkr[0]] = id[u];
    for(int i = head[u], v; ~i; i = cw[i].nex) {
        v = cw[i].v;
        if(v == ba || vis[i] || vis[i^1]) continue;
        dfs_dep(f, v, u, w + cw[i].w);
    }
}
bool cmpl(const int&a, const int&b) {
    return stkl[a] < stkl[b];
}
bool cmpr(const int&a, const int&b) {
    return stkr[a] < stkr[b];
}
void dfs_ans(int u, int _n) {
    if(_n <= 1) return;
    hvy = hvysiz = -1;
    dfs_pre(u, 0, _n);
//    printf("--%d %d %d %d
", u, hvysiz, cw[hvy].u, cw[hvy].v);
    int tmphvy = hvy, tmpsiz = hvysiz;
    vis[tmphvy] = vis[tmphvy^1] = 1;
    stkl[0] = stkr[0] = 0;
    dfs_dep(1, cw[tmphvy].u, -1, 0), dfs_dep(0, cw[tmphvy].v, -1, 0);
    for(int i = 1; i <= stkl[0]; ++i) sdl[i] = i;
//    for(int i = 1; i <= stkl[0]; ++i) printf("%d ", stkl[i]);
//    printf("
");
//    for(int i = 1; i <= stkl[0]; ++i) printf("%d ", suml[i]);
//    printf("
");
    for(int i = 1; i <= stkr[0]; ++i) sdr[i] = i;
//    for(int i = 1; i <= stkr[0]; ++i) printf("%d ", sumr[i]);
//    printf("
");
    sort(sdl + 1, sdl + stkl[0] + 1, cmpl), sort(sdr + 1, sdr + stkr[0] + 1, cmpr);
    for(int i = 1; i <= stkr[0]; ++i) sum[i] = sum[i-1] + sumr[sdr[i]];
//    for(int i = 1; i <= stkr[0]; ++i) printf("%d ", sum[i]);
//    printf("
");
//    for(int i = 1; i <= stkr[0]; ++i) printf("%d ", stkr[sdr[i]]);
//    printf("
");
//    sort(stkl + 1, stkl + 1 + stkl[0]), sort(stkr + 1, stkr + 1 + stkr[0]);
    for(int i = 1, j = stkr[0]; i <= stkl[0]; ++i) {
//        printf("%d ", stkl[sdl[i]]);
        while(j >= 1 && stkl[sdl[i]] + cw[tmphvy].w + stkr[sdr[j]] > m) -- j;
        if(suml[sdl[i]]) ans += big(0, sum[j]);
    }
//    printf("
[%d]
", ans);
    dfs_ans(cw[tmphvy].u, _n - tmpsiz), dfs_ans(cw[tmphvy].v, tmpsiz);
}
void redfs(int u, int ba) {
    for(int i = head[u], v; ~i; i = cw[i].nex) {
        v = cw[i].v;
        if(v == ba) continue;
        redfs(v, u);
        vs[u].eb(mk(v, cw[i].w));
    }
}
void rebuild() {
    redfs(1, 0);
    tot = -1;
    for(int i = 1; i <= n + n; ++i) head[i] = -1;
    for(int i = 1, tx, ty; i <= n; ++i) {
        if(SZ(vs[i]) <= 2) {
            for(int j = 0; j < SZ(vs[i]); ++j) add_edge(i, vs[i][j].fi, vs[i][j].se);
        }else if(SZ(vs[i]) > 2) {
            tx = ++ n, ty = ++ n;
            add_edge(i, tx, 0), add_edge(i, ty, 0);
            for(int j = 0; j < SZ(vs[i]); ++j) {
                if(j & 1) vs[ty].eb(vs[i][j]);
                else vs[tx].eb(vs[i][j]);
            }
        }
    }
}
void dfs(int u, int ba) {
    for(int i = head[u]; ~i; i = cw[i].nex) {
        if(cw[i].v == ba) continue;
        printf("*%d %d %d %d
", cw[i].v, u, id[u], cw[i].w);
        dfs(cw[i].v, u);
    }
}
int main() {
    while(~scanf("%d%d", &n, &m) && (n + m)) {
        for(int i = 1; i <= n; ++i) head[i] = -1, id[i] = 1;
        tot = -1;
        for(int i = 1, a, b, c; i < n; ++i) {
            scanf("%d%d%d", &a, &b, &c);
            add_edge(a, b, c);
        }
        tn = tot;
        rebuild();
//        dfs(1, 0);
        ans = 0;
        dfs_ans(1, n);
        printf("%lld
", ans);
        for(int i = 0; i <= tot; ++i)  vis[i] = 0;
        for(int i = 0; i <= n; ++i) vs[i].clear(), id[i] = 0;
    }
    return 0;
}
//暴力二叉树建图(一个和原节点对应一个虚节点 300ms
const int MXN = 3e4 + 7;
const int MXE = 6e4 + 7;
int n, m;
struct lp{
    int v, nex;
    int w, u;
} cw2[MXE];
int tot2, head2[MXN];
int tot, head[MXN], siz[MXN], hvy, hvysiz, vis[MXE];
int stkl[MXN], stkr[MXN], suml[MXN], sumr[MXN], id[MXN], sdl[MXN], sdr[MXN], sum[MXN];
LL ans;
void add_edge2(int a, int b, int c) {
    cw2[++ tot2].v = b, cw2[tot2].nex = head2[a], cw2[tot2].w = c, cw2[tot2].u = a;
    head2[a] = tot2;
    cw2[++ tot2].v = a, cw2[tot2].nex = head2[b], cw2[tot2].w = c, cw2[tot2].u = b;
    head2[b] = tot2;
}
void dfs_pre(int u, int ba, int _tn) {
    siz[u] = 1;
    for(int i = head2[u], v; ~i; i = cw2[i].nex) {
        v = cw2[i].v;
        if(v == ba || vis[i] || vis[i^1]) continue;
        dfs_pre(v, u, _tn);
        siz[u] += siz[v];
        if(hvy == -1 || big(hvysiz, _tn - hvysiz) > big(siz[v], _tn - siz[v])) {
            hvy = i;
            hvysiz = siz[v];
        }
    }
}
void dfs_dep(int f, int u, int ba, int w) {
    if(f) stkl[++stkl[0]] = w, suml[stkl[0]] = id[u];
    else stkr[++stkr[0]] = w, sumr[stkr[0]] = id[u];
    for(int i = head2[u], v; ~i; i = cw2[i].nex) {
        v = cw2[i].v;
        if(v == ba || vis[i] || vis[i^1]) continue;
        dfs_dep(f, v, u, w + cw2[i].w);
    }
}
bool cmpl(const int&a, const int&b) {
    return stkl[a] < stkl[b];
}
bool cmpr(const int&a, const int&b) {
    return stkr[a] < stkr[b];
}
void dfs_ans(int u, int _n) {
    if(_n <= 1) return;
    hvy = hvysiz = -1;
    dfs_pre(u, 0, _n);
//    printf("--%d %d %d %d
", u, hvysiz, cw[hvy].u, cw[hvy].v);
    int tmphvy = hvy, tmpsiz = hvysiz;
    vis[tmphvy] = vis[tmphvy^1] = 1;
    stkl[0] = stkr[0] = 0;
    dfs_dep(1, cw2[tmphvy].u, -1, 0), dfs_dep(0, cw2[tmphvy].v, -1, 0);
    for(int i = 1; i <= stkl[0]; ++i) sdl[i] = i;
//    for(int i = 1; i <= stkl[0]; ++i) printf("%d ", stkl[i]);
//    printf("
");
//    for(int i = 1; i <= stkl[0]; ++i) printf("%d ", suml[i]);
//    printf("
");
    for(int i = 1; i <= stkr[0]; ++i) sdr[i] = i;
//    for(int i = 1; i <= stkr[0]; ++i) printf("%d ", sumr[i]);
//    printf("
");
    sort(sdl + 1, sdl + stkl[0] + 1, cmpl), sort(sdr + 1, sdr + stkr[0] + 1, cmpr);
    for(int i = 1; i <= stkr[0]; ++i) sum[i] = sum[i-1] + sumr[sdr[i]];
//    for(int i = 1; i <= stkr[0]; ++i) printf("%d ", sum[i]);
//    printf("
");
//    for(int i = 1; i <= stkr[0]; ++i) printf("%d ", stkr[sdr[i]]);
//    printf("
");
//    sort(stkl + 1, stkl + 1 + stkl[0]), sort(stkr + 1, stkr + 1 + stkr[0]);
    for(int i = 1, j = stkr[0]; i <= stkl[0]; ++i) {
//        printf("%d ", stkl[sdl[i]]);
        while(j >= 1 && stkl[sdl[i]] + cw2[tmphvy].w + stkr[sdr[j]] > m) -- j;
        if(suml[sdl[i]]) ans += big(0, sum[j]);
    }
//    printf("
[%d]
", ans);
    dfs_ans(cw2[tmphvy].u, _n - tmpsiz), dfs_ans(cw2[tmphvy].v, tmpsiz);
}

lp cw[MXE];
void add_edge(int a, int b, int c) {
    cw[++ tot].v = b, cw[tot].nex = head[a], cw[tot].w = c, cw[tot].u = a;
    head[a] = tot;
    cw[++ tot].v = a, cw[tot].nex = head[b], cw[tot].w = c, cw[tot].u = b;
    head[b] = tot;
}
vector<pii> vs;
void redfs(int u, int ba) {
    vs.clear();
    for(int i = head[u], v; ~i; i = cw[i].nex) {
        v = cw[i].v;
        if(v == ba) continue;
        vs.eb(mk(cw[i].v, cw[i].w));
    }
    if(SZ(vs) <= 2) {
        for(int i = 0; i < SZ(vs); ++i) add_edge2(u, vs[i].fi, vs[i].se);
    }else {
        int lst = -1;
        for(int i = 1; i < SZ(vs); ++i) {
            if(i == SZ(vs) - 1) {
                add_edge2(u, lst, 0);
                add_edge2(u, vs[i].fi, vs[i].se);
            }else if(i == 1) {
                lst = ++ n;
                add_edge2(lst, vs[i-1].fi, vs[i-1].se);
                add_edge2(lst, vs[i].fi, vs[i].se);
            }else {
                add_edge2(n + 1, lst, 0);
                add_edge2(n + 1, vs[i].fi, vs[i].se);
                lst = ++ n;
            }
        }
    }
    for(int i = head[u], v; ~i; i = cw[i].nex) {
        v = cw[i].v;
        if(v == ba) continue;
        redfs(v, u);
    }
}
void rebuild() {
    tot2 = -1;
    for(int i = 1; i <= n + n; ++i) head2[i] = -1;
    redfs(1, 0);
}
void dfs(int u, int ba) {
//    cerr << u << " " << ba << endl;
    for(int i = head2[u]; ~i; i = cw2[i].nex) {
        if(cw2[i].v == ba) continue;
//        printf("*%d %d %d %d
", cw2[i].v, u, id[u], cw2[i].w);
        dfs(cw2[i].v, u);
    }
}
int main() {
    while(~scanf("%d%d", &n, &m) && (n + m)) {
        for(int i = 1; i <= n; ++i) head[i] = -1, id[i] = 1;
        tot = -1;
        for(int i = 1, a, b, c; i < n; ++i) {
            scanf("%d%d%d", &a, &b, &c);
            add_edge(a, b, c);
        }
        rebuild();
        ans = 0;
        dfs_ans(1, n);
        printf("%lld
", ans);
        for(int i = 0; i <= tot2; ++i)  vis[i] = 0;
        for(int i = 0; i <= n; ++i) id[i] = 0;
    }
    return 0;
}

动态点分治(点分树)

裸题:洛谷P2056(ZJOI2007)捉迷藏, BZOJ3730震波
题目:CF757G , CF100633D
感觉动态点分治利用点分树的特性使得看似暴力的解法变得合理。毕竟点分树层数在(log(n))级别。

洛谷p2056这道裸题来说:
对每个点维护其在点分树上子树内所有点到它父亲节点的距离信息,和该节点在点分树上每个子节点的所在子树内离他最远的距离(距离信息只需要最远和次远的即可,参考别人用优先队列封装了一个堆)
每次更新就暴力沿着点分树向上更新即可。
复杂度:(O(nlog(n)^2))

const int MXN = 2e5 + 7;
const int MXE = 2e6 + 7;
int n, m;
struct lp {
    int v, nex;
    int w;
} cw[MXE];
int tot, head[MXN], siz[MXN], hvy, hvysiz, vis[MXE];
int col[MXN], dep[MXN], fa[MXN], dis[MXN][20];
namespace LCA {
    int dis[MXN], up[MXN][20];
    void dfs(int u, int ba, int d) {
        up[u][0] = ba; dis[u] = d;
        for(int i = 1; i < 20; ++i) up[u][i] = up[up[u][i-1]][i-1];
        for(int i = head[u], v; ~i; i = cw[i].nex) {
            v = cw[i].v;
            if(v == ba) continue;
            dfs(v, u, d + 1);
        }
    }
    int lca(int x, int y) {
        if(dis[x] < dis[y]) swap(x, y);
        for(int i = 19; i >= 0; --i) {
            if(dis[up[x][i]] >= dis[y]) {
                x = up[x][i];
            }
        }
        if(x == y) return x;
        for(int i = 19; i >= 0; --i) {
            if(up[x][i] != up[y][i]) {
                x = up[x][i], y = up[y][i];
            }
        }
        return up[x][0];
    }
    int query(int i, int j) {
        return dis[i] + dis[j] - 2 * dis[lca(i, j)];
    }
}
struct heap {
    priority_queue<int> A, B;  // heap=A-B
    void insert(int x) { A.push(x); }
    void erase(int x) { B.push(x); }
    int top() {
        while (!B.empty() && A.top() == B.top()) A.pop(), B.pop();
        return A.top();
    }
    void pop() {
        while (!B.empty() && A.top() == B.top()) A.pop(), B.pop();
        A.pop();
    }
    int top2() {
        int t = top(), ret;
        pop();
        ret = top();
        A.push(t);
        return ret;
    }
    int size() { return A.size() - B.size(); }
} disf[MXN], dison[MXN], ans;
void add_edge(int a, int b) {
    cw[++ tot].v = b, cw[tot].nex = head[a];
    head[a] = tot;
    cw[++ tot].v = a, cw[tot].nex = head[b];
    head[b] = tot;
}
int get_dis(int i, int j) {
    if(i == j) return 0;
    if(dis[i][dep[i] - dep[j]]) return dis[i][dep[i] - dep[j]];
    dis[i][dep[i] - dep[j]] = LCA::query(i, j);
    return dis[i][dep[i] - dep[j]];
}
void dfs_pre(int u, int ba, int _tn) {
    int mm = 0;
    siz[u] = 1;
    for(int i = head[u], v; ~i; i = cw[i].nex) {
        v = cw[i].v;
        if(v == ba || vis[v]) continue;
        dfs_pre(v, u, _tn);
        siz[u] += siz[v];
        mm = big(mm, siz[v]);
    }
    mm = big(mm, _tn - siz[u]);
    if(hvy == -1 || hvysiz > mm) {
        hvy = u;
        hvysiz = mm;
    }
}
void dfs_dis(int u, int ba, int d, int rt) {
    disf[rt].insert(d);
    for(int i = head[u], v; ~i; i = cw[i].nex) {
        v = cw[i].v;
        if(v == ba || vis[v]) continue;
        dfs_dis(v, u, d + 1, rt);
    }
}
void dfs_get(int u, int _n, int f) {
    if(f) hvy = hvysiz = -1;
    else assert(hvy == u);
    if(f) dfs_pre(u, -1, _n);
//    debug(u, _n, hvy)
    int lstrt = hvy;
    vis[lstrt] = 1;
    for(int i = head[lstrt], v; ~i; i = cw[i].nex) {
        v = cw[i].v;
        if(v == lstrt || vis[v]) continue;
        hvy = hvysiz = -1;
        dfs_pre(v, -1, siz[v]);
        dfs_dis(v, -1, 1, hvy);
        fa[hvy] = lstrt;
        dep[hvy] = dep[lstrt] + 1;
//        debug(hvy, dep[hvy])
        dison[lstrt].insert(disf[hvy].top());
        dfs_get(hvy, siz[v], 0);
    }
    if(SZ(dison[lstrt]) >= 2) {
        ans.insert(dison[lstrt].top() + dison[lstrt].top2());
    }else if(SZ(dison[lstrt]))ans.insert(dison[lstrt].top());
}
int main() {
#ifndef ONLINE_JUDGE
    freopen("/home/cwolf9/CLionProjects/ccc/in.txt", "r", stdin);
    //freopen("/home/cwolf9/CLionProjects/ccc/out.txt", "w", stdout);
#endif
    n = read();
    for(int i = 1; i <= n; ++i) head[i] = -1;
    tot = -1;
    for(int i = 1, a, b; i < n; ++i) {
        a = read(), b = read();
        add_edge(a, b);
    }
    LCA::dfs(1, 0, 1);
    dfs_get(1, n, 1);
    m = read();
//    debug(m, get_dis(1, 3), dep[1], dep[3])
    char op[3];
    int x, cnt = n;
    while(m --) {
        scanf("%s", op);
        if(op[0] == 'G') {
            if(cnt == 0) printf("-1
");
            else if(cnt == 1) printf("0
");
            else printf("%d
", ans.top());
        }else {
            x = read();
            if(col[x] == 0) {
                if(SZ(dison[x]) == 1) ans.erase(dison[x].top());
                for(int i = x; fa[i]; i = fa[i]) {
                    if(SZ(dison[fa[i]]) >= 2) ans.erase(dison[fa[i]].top() + dison[fa[i]].top2());
                    else if(col[fa[i]] == 0 && SZ(dison[fa[i]]) == 1) ans.erase(dison[fa[i]].top());
                    dison[fa[i]].erase(disf[i].top());
                    disf[i].erase(get_dis(x, fa[i]));
                    if(disf[i].size()) dison[fa[i]].insert(disf[i].top());
                    if(SZ(dison[fa[i]]) >= 2) ans.insert(dison[fa[i]].top() + dison[fa[i]].top2());
                    else if(col[fa[i]] == 0 &&SZ(dison[fa[i]])) ans.insert(dison[fa[i]].top());
                }
                col[x] = 1;
                -- cnt;
            }else {
                if(SZ(dison[x]) == 1) ans.insert(dison[x].top());
                for(int i = x; fa[i]; i = fa[i]) {
                    if(SZ(dison[fa[i]]) >= 2) ans.erase(dison[fa[i]].top() + dison[fa[i]].top2());
                    else if(col[fa[i]] == 0 &&SZ(dison[fa[i]]) == 1) ans.erase(dison[fa[i]].top());
                    if(SZ(disf[i])) dison[fa[i]].erase(disf[i].top());
                    disf[i].insert(get_dis(x, fa[i]));
                    dison[fa[i]].insert(disf[i].top());
                    if(SZ(dison[fa[i]]) >= 2) ans.insert(dison[fa[i]].top() + dison[fa[i]].top2());
                    else if(col[fa[i]] == 0 &&SZ(dison[fa[i]])) ans.insert(dison[fa[i]].top());
                }
                col[x] = 0;
                ++ cnt;
            }
        }
    }
#ifndef ONLINE_JUDGE
    cout << "time cost:" << 1.0*clock()/CLOCKS_PER_SEC << "ms" << endl;
#endif
    return 0;
}

/*
 * http://wiki.gyh.me/DP/%E6%A0%91%E5%88%86%E6%B2%BB/
 */

bzoj3730震波
疯狂tle,好像网上动态点分治的代码全都过不了。。

const int MXN = 2e5 + 7;
const int MXE = 2e5 + 7;
int n, m;
const int N = 100002;
struct lp {
    int v, nex;
    int w;
} cw[MXE];
int tot, head[MXN], siz[MXN], hvy, hvysiz;
bool vis[MXN];
int ar[MXN], dep[MXN], fa[MXN];
int dis[MXN][20];
namespace LCA {
    int dis[MXN], up[MXN][20], lg[MXN];
    void dfs(int u, int ba) {
        for(int i = head[u], v; ~i; i = cw[i].nex) {
            v = cw[i].v;
            if(v == ba) continue;
            dis[v] = dis[u] + 1, up[v][0] = u;
            dfs(v, u);
        }
    }
    void init() {
        for (int i = 2; i <= n; ++i) lg[i] = lg[i / 2] + 1;;
        dis[1] = 1;
        dfs(1, -1);
        for (int j = 1; j <= lg[n]; ++j)
            for (int i = 1; i <= n; ++i) up[i][j] = up[up[i][j - 1]][j - 1];
    }
    int lca(int x, int y) {
        if (dis[x] > dis[y]) swap(x, y);
        int k = dis[y] - dis[x];
        for (int i = 0; k; k = k / 2, ++i)
            if (k & 1) y = up[y][i];
        if (x == y) return x;
        k = dis[x];
        for (int i = lg[k]; i >= 0; --i)
            if (up[x][i] != up[y][i]) x = up[x][i], y = up[y][i];
        return up[x][0];
    }
    int query(int i, int j) {
        return dis[i] + dis[j] - 2 * dis[lca(i, j)];
    }
}
int get_dis(int i, int j) {
    if(i == j) return 0;
    if(dis[i][dep[i] - dep[j]]) return dis[i][dep[i] - dep[j]];
    dis[i][dep[i] - dep[j]] = LCA::query(i, j);
    return dis[i][dep[i] - dep[j]];
}
struct heap {
    static const int MAXE = N*60;
    int rt[MXN], tot;
    int sum[MAXE], ls[MAXE], rs[MAXE];
    void update(int p, int v, int l, int r, int&rt) {
        if(rt == 0) rt = ++ tot;
        if(l == r) {
            sum[rt] += v;
            return;
        }
        int mid = (l + r) >> 1;
        if(p <= mid) update(p, v, l, mid, ls[rt]);
        else update(p, v, mid + 1, r, rs[rt]);
        sum[rt] = sum[ls[rt]] + sum[rs[rt]];
    }
    int query(int L, int R, int l, int r, int rt) {
        if(L > R || rt == 0 || L > r || R < l) return 0;
        if(L <= l && r <= R) return sum[rt];
        int mid = (l + r) >> 1;
        if(L > mid) return query(L, R, mid + 1, r, rs[rt]);
        else if(R <= mid) return query(L,R,l,mid,ls[rt]);
        else {
            return query(L,mid,l,mid,ls[rt])+query(mid+1,R,mid+1,r,rs[rt]);
        }
    }
} dison, disfa;
inline void add_edge(int a, int b) {
    cw[++ tot].v = b, cw[tot].nex = head[a];
    head[a] = tot;
    cw[++ tot].v = a, cw[tot].nex = head[b];
    head[b] = tot;
}
int _tn;
void dfs_pre(int u, int ba) {
    int mm = 0;
    siz[u] = 1;
    for(int i = head[u], v; ~i; i = cw[i].nex) {
        v = cw[i].v;
        if(v == ba || vis[v]) continue;
        dfs_pre(v, u);
        siz[u] += siz[v];
        mm = big(mm, siz[v]);
    }
    mm = big(mm, _tn - siz[u]);
    if(hvy == -1 || hvysiz > mm) {
        hvy = u;
        hvysiz = mm;
    }
}
void dfs_dis(int u, int ba, int d, int rt) {
    dison.update(d, ar[u], 0, n, dison.rt[rt]);
    siz[u] = 1;
    for(int i = head[u], v; ~i; i = cw[i].nex) {
        v = cw[i].v;
        if(v == ba || vis[v]) continue;
        dfs_dis(v, u, d + 1, rt);
        siz[u] += siz[v];
    }
}
void dfs_fa(int u, int ba, int d, int rt) {
    disfa.update(d, ar[u], 0, n, disfa.rt[rt]);
    for(int i = head[u], v; ~i; i = cw[i].nex) {
        v = cw[i].v;
        if(v == ba || vis[v]) continue;
        dfs_fa(v, u, d + 1, rt);
    }
}
void dfs_get(int u) {
//    debug(u, _n, hvy)
    vis[u] = true;
    dfs_dis(u, -1, 0, u);
    for(int i = head[u], v; ~i; i = cw[i].nex) {
        v = cw[i].v;
        if(vis[v]) continue;
        hvy = hvysiz = -1;
//        int tmp = siz[v];
        _tn = siz[v];
        dfs_pre(v, -1);
        dfs_fa(v, u, 1, hvy);
//        debug(u, v, tmp, siz[v])
//        assert(tmp == siz[v]);
        fa[hvy] = u;
        dep[hvy] = dep[u] + 1;
        dfs_get(hvy);
    }
}
int main() {
    n = read(), m = read();
    for(int i = 1; i <= n; ++i) ar[i] = read(), head[i] = -1;
    tot = -1;
    for(int i = 1, a, b; i < n; ++i) {
        a = read(), b = read();
        add_edge(a, b);
    }
    LCA::init();
    hvy = hvysiz = -1;
    _tn = n;
    dfs_pre(1, -1);
    dep[hvy] = 1;
    dfs_get(hvy);
//    debug(m, get_dis(1, 3), dep[1], dep[3])
    int opt, x, y, lst, lastans = 0;
    while(m --) {
        opt = read(), x = read(), y = read();
        x ^= lastans, y ^= lastans;
        if(opt == 0) {
            lastans = dison.query(0, y, 0, n, dison.rt[x]);
            for(int i = x; fa[i]; i = fa[i]) {
//                debug(i, fa[i])
                lst = get_dis(x, fa[i]);
                lastans += dison.query(0, y - lst, 0, n, dison.rt[fa[i]]) -
                        disfa.query(0, y - lst, 0, n, disfa.rt[i]);
            }
            printf("%d
", lastans);
        }else {
            dison.update(0, y - ar[x], 0, n, dison.rt[x]);
            for(int i = x; fa[i]; i = fa[i]) {
                lst = get_dis(x, fa[i]);
                dison.update(lst, y - ar[x], 0, n, dison.rt[fa[i]]);
                disfa.update(lst, y - ar[x], 0, n, disfa.rt[i]);
            }
            ar[x] = y;
        }
    }
    return 0;
}

其他

KD-Tree

bzoj2648,bzoj2716

概念参考:guoziqing506, 拳四郎, July_
两种码风:devil-gary, RZZ

const int INF = 0x3f3f3f3f;
const int MXN = 5e5 + 7;
const int MXE = 1e6 + 7;
int n, m, Q;
int ans;
//动态开点
const int K = 2;
struct P {
    int x[K];
}ap[MXN], pt;
struct KDT {
    int x[K], Min[K], Max[K], split;
    int ls, rs;
}kdt[MXE];
int kdtNode, kdtRt;
int cmp_k;
bool cmp(const P&a, const P&b) {
    return a.x[cmp_k] < b.x[cmp_k];
}
void push_up(int rt) {
    int lc = kdt[rt].ls;
    if(lc) {
        for(int i = 0; i < K; ++i) {
            kdt[rt].Min[i] = sml(kdt[rt].Min[i], kdt[lc].Min[i]);
            kdt[rt].Max[i] = big(kdt[rt].Max[i], kdt[lc].Max[i]);
        }
    }
    lc = kdt[rt].rs;
    if(lc) {
        for(int i = 0; i < K; ++i) {
            kdt[rt].Min[i] = sml(kdt[rt].Min[i], kdt[lc].Min[i]);
            kdt[rt].Max[i] = big(kdt[rt].Max[i], kdt[lc].Max[i]);
        }
    }
}
void build(int l, int r, int &rt) {
    if(l > r) {
        rt = 0;
        return;
    }
    rt = ++ kdtNode;
    int d = 0;
    double mx = -1, ave, sum;
    for(int i = 0; i < K; ++i) {
        ave = sum = 0;
        for(int j = l; j <= r; ++j) ave += ap[j].x[i]; ave /= r-l+1;
        for(int j = l; j <= r; ++j) sum += o2(ap[j].x[i] - ave);
        if(sum > mx) mx = sum, d = i;
    }
    kdt[rt].split = cmp_k = d;
    int mid = (l + r) >> 1;
    nth_element(ap + l, ap + mid + 1, ap + r + 1, cmp);
    for(int i = 0; i < K; ++i) kdt[rt].x[i] = kdt[rt].Min[i] = kdt[rt].Max[i] = ap[mid].x[i];
    build(l, mid - 1, kdt[rt].ls), build(mid + 1, r, kdt[rt].rs);
    push_up(rt);
}
void insert(int &rt, int kd = 0) {
    if(!rt) {
        rt = ++ kdtNode;
        kdt[rt].split = (kd + 1) % K;
        for(int i = 0; i < K; ++i) kdt[rt].x[i] = kdt[rt].Min[i] = kdt[rt].Max[i] = pt.x[i];
        return;
    }
    for(int i = 0; i < K; ++i) {
        kdt[rt].Min[i] = sml(kdt[rt].Min[i], pt.x[i]);
        kdt[rt].Max[i] = big(kdt[rt].Max[i], pt.x[i]);
    }
    int d = kdt[rt].split;
    if(pt.x[d] < kdt[rt].x[d]) insert(kdt[rt].ls, d);
    else insert(kdt[rt].rs, d);
    push_up(rt);//?
}
inline int dist(int *x, int *y) {
    int ret = 0;
    for(int i = 0; i < K; ++i) ret += abs(x[i] - y[i]);
    return ret;
}
inline int dist(int *x, int *y, int *z) {//判断是否有交
    int ret = 0;
    for(int i = 0; i < K; ++i) {
        if(y[i] > x[i]) ret += y[i] - x[i];
        else if(x[i] > z[i]) ret += x[i] - z[i];
    }
    return ret;
}
void knnask(int rt) {
    if(!rt || dist(pt.x, kdt[rt].Min, kdt[rt].Max) >= ans) return;
    ans = sml(ans, dist(kdt[rt].x, pt.x));
    int d = kdt[rt].split;
    if(pt.x[d] < kdt[rt].x[d]) knnask(kdt[rt].ls), knnask(kdt[rt].rs);
    else knnask(kdt[rt].rs), knnask(kdt[rt].ls);
}

int main() {
#ifndef ONLINE_JUDGE
    freopen("/home/cwolf9/CLionProjects/ccc/in.txt", "r", stdin);
//    freopen("/home/cwolf9/CLionProjects/ccc/out.txt", "w", stdout);
#endif
    n = read(), m = read();
    for(int i = 1; i <= n; ++i) {
        for(int j = 0; j < K; ++j) ap[i].x[j] = read();
    }
    kdtNode = kdtRt = 0;
    build(1, n, kdtRt);
    int opt, x, y;
    while(m --) {
        opt = read();
        for(int i = 0; i < K; ++i) pt.x[i] = read();
        if(opt == 1) insert(kdtRt);
        else {
            ans = INF;
            knnask(kdtRt);
            printf("%d
", ans);
        }
    }
    return 0;
}

虚树

虚树就是把关键点从树立面拿出来,再补上他们的lca,形成新的树。
讲解:here
bzoj2286,bzoj3611,cf613D,bzoj3572

namespace VT {
    struct lp {
        int v, nex;
        LL w;
    } cw[MXE];
    int tot, head[MXN], stak[MXN], top, d[MXN], is[MXN];
    void add_edge(int a, int b, LL c) {
        cw[++tot].v = b, cw[tot].nex = head[a], cw[tot].w = c;
        head[a] = tot;
        cw[++tot].v = a, cw[tot].nex = head[b], cw[tot].w = c;
        head[b] = tot;
    }
    bool cmp(const int &a, const int &b) {///tid is dfs number
        return LCA::tid[ar[a]] < LCA::tid[ar[b]];
    }
    void build(int n) {
        tot = head[1] = -1;
        stak[top = 1] = 1;
        for(int i = 1; i <= n; ++i) d[i] = i, is[ar[i]] = 1;
        sort(d + 1, d + 1 + n, cmp);
        for(int i = 1; i <= n; ++i) {
            if(ar[d[i]] == 1) continue;
            int lca = LCA::lca(ar[d[i]], stak[top]);
            if(lca != stak[top]) {
                while(LCA::tid[lca] < LCA::tid[stak[top-1]]) {
                    add_edge(stak[top], stak[top-1], LCA::query(stak[top], stak[top-1]));
                    -- top;
                }
                if(lca == stak[top-1]) {
                    add_edge(stak[top], stak[top-1], LCA::query(stak[top], stak[top-1]));
                    -- top;
                }else {
                    head[lca] = -1;
                    add_edge(lca, stak[top], LCA::query(lca, stak[top]));
                    stak[top] = lca;
                }
            }
            stak[++top] = ar[d[i]];
            head[stak[top]] = -1;
        }
        for(int i = 2; i <= top; ++i) add_edge(stak[i], stak[i-1], LCA::query(stak[i], stak[i-1]));
    }
    LL dp[MXN];
    void dfs(int u, int ba) {
        dp[u] = 0;
        for(int i = head[u], v; ~i; i = cw[i].nex) {
            v = cw[i].v;
            if(v == ba) continue;
            dfs(v, u);
            if(is[v]) dp[u] += cw[i].w;
            else dp[u] += sml(dp[v], cw[i].w);
        }
    }
}

steiner斯坦纳树

2019南昌邀请赛A题HDU4085
这两题可以说几乎一样了,hdu4085只要求前k((kle 5))个点和后k个点两两之间一一对应,但并没有固定谁该和谁对应。
邀请赛A题给定4对点,固定两两之间应该联通。写法差不多,改一下(check())状态的函数即可,合法状态要么不包含给定点对,要么给定点对的两个点都包含。
注意有一个坑点是4对点中可能有重点。

/*
枚举状态sta时,遇到在第一类转移之后有更新的节点,将其加入队列,用spfa做一次迭代更新。普通的转
 移是不能保证最优性的,而spfa采用迭代逼近的方式,将更新过的点再进行更新,可以保证最后每个节点
 都是“最短路”。

对于ZOJ WormHole Transportation 和 HDU Peach Blossom Spring,其解为一片斯坦纳生成
 森林,用dp[sta]数组来维护最优解,可利用f[i][sta]来松弛dp[sta],得到当前状态的最小代价。
 最后由小到大枚举状态,将森林在0代价的条件下合并成“生成树”即可。
 注意在这过程中要过滤掉非法状态。
 */
const int MXN = 1e3 + 7;
const int MXE = 1e4 + 7;
int n, m, stnum;
int head[MXN], tot;
struct lp {
    int v, nex;
    int w;
}cw[MXE];
LL dp[(1<<10) + 5][35], val[MXN], f[(1<<10)+5];
int in[MXN];
queue<int> Q;
string a, b, aa[4], bb[4];
int X[4], Y[4], to[MXN], re[MXN];
map<string, int> mp, mp2;
void add_edge(int u, int v, int w) {
    cw[++tot].v = v, cw[tot].nex = head[u], cw[tot].w = w;
    head[u] = tot;
    cw[++tot].v = u, cw[tot].nex = head[v], cw[tot].w = w;
    head[v] = tot;
}
void spfa(int S) {
    while(!Q.empty()) {
        int u = Q.front(); Q.pop();
        in[u] = 0;
        for(int i = head[u], v; ~i; i = cw[i].nex) {
            v = cw[i].v;
            if(dp[S][v] > dp[S][u] + cw[i].w) {
                dp[S][v] = dp[S][u] + cw[i].w;
                if(!in[v]) Q.push(v), in[v] = 1;
            }
        }
    }
}
void steiner() {
    clr(dp, 0x3f);
    for(int i = 0; i < stnum; ++i) {
        dp[1<<i][re[i]] = 0;
    }
    int sta = 1 << stnum;
    for (int S = 1; S < sta; ++S) {
        for (int x = S; x; x = (x-1)&S) {
            for(int i = 0; i < n; ++i) {
                dp[S][i] = sml(dp[S][i], dp[x][i] + dp[S^x][i]);
            }
        }
        for(int i = 0; i < n; ++i) {
            in[i] = 0;
            if(dp[S][i] != INFLL && !in[i]) {
                Q.push(i), in[i] = 1;
            }
        }
        spfa(S);
    }
}
bool check(int s) {
    bool flag = true;
    for(int i = 0; i < 4; ++i) {
        if(((s>>to[X[i]])&1) != ((s>>to[Y[i]])&1)) flag = false;
    }
    return flag;
}
int main() {
#ifndef ONLINE_JUDGE
    freopen("/home/cwolf9/CLionProjects/ccc/in.txt", "r", stdin);
    //freopen("/home/cwolf9/CLionProjects/ccc/out.txt", "w", stdout);
#endif
    tot = -1;
    cin >> n >> m;
    for(int i = 0; i < n; ++i) {
        cin >> a;
        mp[a] = i;
        head[i] = -1;
    }
    for(int i = 1, x; i <= m; ++i) {
        cin >> a >> b >> x;
        add_edge(mp[a], mp[b], x);
    }
    for(int i = 0; i < 4; ++i) {
        cin >> aa[i] >> bb[i];
        X[i] = mp[aa[i]], Y[i] = mp[bb[i]];
        if(mp2[aa[i]] == 0) to[X[i]] = stnum ++, re[stnum - 1] = X[i];
        if(mp2[bb[i]] == 0) to[Y[i]] = stnum ++, re[stnum - 1] = Y[i];
        mp2[aa[i]] = mp2[bb[i]] = 1;
    }
    steiner();
    int sta = 1 << stnum;
    clr(f, 0x3f);
    for(int i = 1; i < sta; ++i) {
        for(int j = 0; j < n; ++j) f[i] = sml(f[i], dp[i][j]);
    }
//    for(int i = 1; i < sta; ++ i) printf("%d ", f[i]); printf("
");
    for(int i = 1; i < sta; ++i) {
        if(check(i)) {
            for (int x = i; x; x = (x-1)&i) {
                if(check(x)) f[i] = sml(f[i], f[x] + f[i ^ x]);
            }
        }
    }
    cout << f[sta - 1] << endl;
#ifndef ONLINE_JUDGE
    cout << "time cost:" << 1.0*clock()/CLOCKS_PER_SEC << "ms" << endl;
#endif
    return 0;
}

zoj3613

const int MXN = 1e3 + 7;
const int MXE = 1e4 + 7;
int n, m;
int head[MXN], tot;
struct lp {
    int v, nex;
    int w;
}cw[MXE];
int dp[(1<<10) + 5][35], val[MXN], f[(1<<10)+5];
int in[MXN];
queue<int> Q;
int P[MXN], T[MXN], X[MXN], Y[MXN], pnum[MXN], re[MXN], t1, t2, stnum;
void add_edge(int u, int v, int w) {
    cw[++tot].v = v, cw[tot].nex = head[u], cw[tot].w = w;
    head[u] = tot;
    cw[++tot].v = u, cw[tot].nex = head[v], cw[tot].w = w;
    head[v] = tot;
}
void spfa(int S) {
    while(!Q.empty()) {
        int u = Q.front(); Q.pop();
        in[u] = 0;
        for(int i = head[u], v; ~i; i = cw[i].nex) {
            v = cw[i].v;
            if(dp[S][v] > dp[S][u] + cw[i].w) {
                dp[S][v] = dp[S][u] + cw[i].w;
                if(!in[v]) Q.push(v), in[v] = 1;
            }
        }
    }
}
void steiner() {
    clr(dp, 0x3f);
    for(int i = 0; i < stnum; ++i) {
        dp[1<<i][re[i]] = 0;
    }
    int sta = 1 << stnum;
    for (int S = 1; S < sta; ++S) {
        for (int x = S; x; x = (x-1)&S) {
            for(int i = 0; i < n; ++i) {
                dp[S][i] = sml(dp[S][i], dp[x][i] + dp[S^x][i]);
            }
        }
        for(int i = 0; i < n; ++i) {
            in[i] = 0;
            if(dp[S][i] != INFLL && !in[i]) {
                Q.push(i), in[i] = 1;
            }
        }
        spfa(S);
    }
}
bool check(int s) {
    int cnt = 0;
    for(int i = 0; i < stnum; ++i) if(s&(1<<i)) cnt += pnum[i];
    return cnt >= 0;
}
int get(int s) {
    int cnt = 0, cnt2 = 0;
    for(int i = 0; i < stnum; ++i) {
        if(s&(1<<i)) {
            if (pnum[i] >= 0) cnt += pnum[i];
            else cnt2 -= pnum[i];
        }
    }
    if(cnt <= cnt2) return cnt;
    return 0;
}
int main() {
#ifndef ONLINE_JUDGE
    freopen("/home/cwolf9/CLionProjects/ccc/in.txt", "r", stdin);
    //freopen("/home/cwolf9/CLionProjects/ccc/out.txt", "w", stdout);
#endif
    tot = -1;
    n = read();
    for(int i = 0; i < n; ++i) {
        P[i] = read(), T[i] = read();
        if(P[i] && T[i]) -- P[i], -- T[i];
        if(P[i] || T[i]) {
            pnum[stnum] = P[i] - T[i];
            re[stnum] = i;
            ++ stnum;
        }
        head[i] = -1;
    }
    m = read();
    for(int i = 1, u, v, w; i <= m; ++i) {
        u = read(), v = read(), w = read();
        add_edge(u - 1, v - 1, w);
    }
    steiner();
    int sta = 1 << stnum;
    clr(f, 0x3f);
    for(int i = 1; i < sta; ++i) {
        for(int j = 0; j < n; ++j) f[i] = sml(f[i], dp[i][j]);
    }
//    for(int i = 1; i < sta; ++ i) printf("%d ", f[i]); printf("
");
    for(int i = 1; i < sta; ++i) {
        if(check(i)) {
            for (int x = i; x; x = (x-1)&i) {
                if(check(x) && check(i ^ x)) {
//                    debug(i, x, i ^ x, f[i], f[x], f[i^x])
                    f[i] = sml(f[i], f[x] + f[i ^ x]);
                }
            }
        }
    }
    int Maxnum = 0, Mincost = 0;
    for(int i = 1; i < sta; ++i) {
        if(f[i] != INF) {
            int num = get(i);
            if(num > Maxnum) {
                Maxnum = num;
                Mincost = f[i];
            }else if(num == Maxnum && f[i] < Mincost) {
                Mincost = f[i];
            }
        }
    }
    printf("%d %d
", Maxnum, Mincost);
#ifndef ONLINE_JUDGE
    cout << "time cost:" << 1.0*clock()/CLOCKS_PER_SEC << "ms" << endl;
#endif
    return 0;
}

DSU on Tree 2019南昌icpc K题

#pragma comment(linker, "/STACK:102400000,102400000")
#include <bits/stdc++.h>
#define fi first
#define se second
#define endl '
'
#define mk make_pair
#define eb push_back
#define SZ(x) ((int)(x).size())
#define all(x) (x).begin(), (x).end()
#define clr(a, b) memset((a),(b),sizeof((a)))
#define iis std::ios::sync_with_stdio(false); cin.tie(0)
#define my_unique(x) sort(all(x)),x.erase(unique(all(x)),x.end())
using namespace std;
#pragma optimize("-O3")
typedef long long LL;
typedef unsigned long long uLL;
typedef pair<int, int> pii;
inline LL read() {
    LL x = 0;int f = 0;
    char ch = getchar();
    while (ch < '0' || ch > '9') f |= (ch == '-'), ch = getchar();
    while (ch >= '0' && ch <= '9') x = (x << 3) + (x << 1) + ch - '0', ch = getchar();
    return x = f ? -x : x;
}
inline void write(LL x, bool f) {
    if (x == 0) {putchar('0'); if(f)putchar('
');else putchar(' ');return;}
    if (x < 0) {putchar('-');x = -x;}
    static char s[23];
    int l = 0;
    while (x != 0)s[l++] = x % 10 + 48, x /= 10;
    while (l)putchar(s[--l]);
    if(f)putchar('
');else putchar(' ');
}
int lowbit(int x) { return x & (-x); }
void debug_out() { cerr << '
'; }
template<typename T, typename ...R>void debug_out(const T &f, const R &...r) {cerr << f << " ";debug_out(r...);}
#define debug(...) cerr << "[" << #__VA_ARGS__ << "]: ", debug_out(__VA_ARGS__);
 
const LL INFLL = 0x3f3f3f3f3f3f3f3fLL;
const int mod = 998244353;
const int MOD = 1e9 + 7;
const int INF = 0x3f3f3f3f;
const int MXN = 1e5 + 7;
const int MXE = 2e5 + 7;

int n, m;
int dis[MXN], ar[MXN];
std::vector<int> mp[MXN];
map<pii, int> od[MXN];
LL ans;
map<pii, int>::iterator sit;
void dfs(int u, int ba) {
    dis[u] = dis[ba] + 1;
    for(auto v: mp[u]) {
        dfs(v, u);
        if((int)od[v].size() > (int)od[u].size()) swap(od[u], od[v]);
        for(sit = od[v].begin(); sit != od[v].end(); ++ sit) {
            int D = (*sit).fi.fi, V = (*sit).fi.se;
            D = 2 * dis[u] - D + m;
            V = 2 * ar[u] - V;
            ans += od[u][mk(D, V)] * (*sit).se;
        }
        for(sit = od[v].begin(); sit != od[v].end(); ++ sit) od[u][(*sit).fi] += (*sit).se;
        od[v].clear();
    }
    od[u][mk(dis[u], ar[u])] += 1;
}
int main() {
#ifndef ONLINE_JUDGE
    freopen("E://ADpan//in.in", "r", stdin);
    // freopen("E://ADpan//out.out", "w", stdout);
#endif
    n = read(), m = read();
    for(int i = 1; i <= n; ++i) ar[i] = read();
    for(int i = 2, x; i <= n; ++i) {
        x = read();
        mp[x].eb(i);
    }
    dfs(1, 0);
    printf("%lld
", ans * 2);
#ifndef ONLINE_JUDGE
    cout << "time cost:" << 1.0*clock()/CLOCKS_PER_SEC << "ms" << endl;
#endif
    return 0;
}
原文地址:https://www.cnblogs.com/Cwolf9/p/11297903.html