码迷,mamicode.com
首页 > 其他好文 > 详细

省选前的数据结构和字符串训练合编

时间:2021-03-01 12:59:52      阅读:0      评论:0      收藏:0      [点我收藏+]

标签:gis   dep   getc   多源   pid   font   alc   hnoi   sdoi   

虚树

[SDOI2011]消耗战

板题,基本上是对着网上的板子敲的

#include <bits/stdc++.h>
using namespace std;
 
 
inline int read() {
    int out = 0;
    register char cc = getchar();
    while (cc < 0 || cc > 9) cc = getchar();
    while (cc >= 0 && cc <= 9) out = (out << 3) + (out << 1) + (cc ^ 48), cc = getchar();
    return out;
}
 
inline void write(long long x) {
    if (x == 0) putchar(0);
    else {
        int num = 0;
        char c[20];
        while (x) c[++num] = x % 10 + 48, x /= 10;
        while (num) putchar(c[num--]);
    }
    putchar(\n);
}
 
 
int N, M, K, a, b, c, Id[500010];
 
 
int head[500010], nxt[1000010], to[1000010], edge[1000010], cnt;
 
void add_edge(int u, int v, int w) {
    to[++cnt] = v;
    edge[cnt] = w;
    nxt[cnt] = head[u];
    head[u] = cnt;
}
 
void add(int u, int v) {
    to[++cnt] = v;
    nxt[cnt] = head[u];
    head[u] = cnt;
}
 
 
int dfn[500010], tim;
int f[500010][19], dep[500010]; 
long long Min[500010];
 
void dfs(int u, int fa) {
    dep[u] = dep[fa] + 1;
    f[u][0] = fa;
    dfn[u] = ++tim;
    for (int i = 1; i < 19; i++) f[u][i] = f[f[u][i - 1]][i - 1];
    for (int i = head[u]; i; i = nxt[i]) {
        int v = to[i];
        if (v == fa) continue;
        Min[v] = (Min[u] < edge[i] ? Min[u] : edge[i]);
        dfs(v, u);
    }
}
 
 
int Lca(int x, int y) {
    if (dep[x] < dep[y]) swap(x, y);
    for (int i = 18; i >= 0; i--) if (dep[f[x][i]] >= dep[y]) x = f[x][i];
    if (x == y) return x;
    for (int i = 18; i >= 0; i--) if (f[x][i] != f[y][i]) x = f[x][i], y = f[y][i];
    return f[x][0];
}
 
 
inline bool cmp(const int &g, const int &h) {
    return dfn[g] < dfn[h];
}
 
 
int Stack[500010], tot;
 
void Insert(int x) {
    if (tot == 1) {
        Stack[++tot] = x; 
        return ;
    }
    int lca = Lca(x, Stack[tot]);
    if (lca == Stack[tot]) return ;
    while (tot > 1 && dfn[lca] <= dfn[Stack[tot - 1]]) add(Stack[tot - 1], Stack[tot]), tot--;
    if (lca != Stack[tot]) add(lca, Stack[tot]), Stack[tot] = lca;
    Stack[++tot] = x;
}
 
 
long long dp(int u) {
    long long ans = 0;
    for (int i = head[u]; i; i = nxt[i]) ans = ans + dp(to[i]);
    if (ans == 0) ans = 1LL << 60;
    head[u] = 0;
    return min(ans, Min[u]);
}
 
 
int main() {
    N = read();
    for (int i = 1; i < N; i++) {
        a = read(), b = read(), c = read();
        add_edge(a, b, c);
        add_edge(b, a, c);
    }
    Min[1] = 1LL << 60;
    dfs(1, 0);
    memset(head, 0, sizeof(head));
    for (M = read(); M; M--) {
        K = read(), cnt = 0;
        for (int i = 1; i <= K; i++) Id[i] = read();
        sort(Id + 1, Id + K + 1, cmp);
        Stack[tot = 1] = 1;
        for (int i = 1; i <= K; i++) Insert(Id[i]);
        while (tot) add(Stack[tot - 1], Stack[tot]), tot--; 
        write(dp(1));
    }
    return 0;
}

 

「HNOI2014」世界树

虚树+树形DP+倍增

每次把议事处构成的虚树先建出来 $\Theta(\sum m_i\ log\ n)$

然后换根DP,求到每个虚树上的点的最近议事处 $\Theta(\sum m_i)$ (ps:你要多源最短路也行,慢一点)

最后对每条虚树上的边(实际在原树中为一条链),直接算出分界点(链上哪些属于上端,哪些属于下端),从下端点到上端点倍增即可 $\Theta(\sum m_i\ log\ n)$

思路挺简单的,细节对蒟蒻来说有一点点多

#include <bits/stdc++.h>

using namespace std;


inline int read() {
    int out = 0; bool flag = false;
    register char cc = getchar();
    while (cc < 0 || cc > 9) {
        if (cc == -) flag = true;
        cc = getchar();
    }
    while (cc >= 0 && cc <= 9) {
        out = (out << 3) + (out << 1) + (cc ^ 48);
        cc = getchar();
    }
    return flag ? -out : out;
}

inline void write(int x, char ch) {
    if (x < 0) putchar(-), x = -x;
    if (x == 0) putchar(0);
    else {
        int num = 0; char cc[22];
        while (x) cc[++num] = x % 10 + 48, x /= 10;
        while (num) putchar(cc[num--]);
    }
    putchar(ch);
}

const int N = 3e5 + 10;

int n, m, id[N], Id[N], ans[N];

int head[N], to[N << 1], nxt[N << 1], cnt;

void add_edge(int u, int v) {
    to[++cnt] = v, nxt[cnt] = head[u], head[u] = cnt;
}

int dep[N], f[N][19], dfn[N], times, sze[N], s[N][19];

void dfs(int u, int fa) {
    dep[u] = dep[fa] + 1, f[u][0] = fa, dfn[u] = ++times;
    for (int i = 1; i <= 18; i++) f[u][i] = f[f[u][i - 1]][i - 1];
    sze[u] = 1;
    for (int i = head[u]; i; i = nxt[i]) {
        int v = to[i]; 
        if (v == fa) continue;
        dfs(v, u), sze[u] += sze[v]; 
    }
    for (int i = head[u]; i; i = nxt[i]) {
        int v = to[i];
        if (v == fa) continue;
        s[v][0] = sze[u] - sze[v];
    }
}

void count(int u, int fa) {
    for (int i = 1; i <= 18; i++) s[u][i] = s[u][i - 1] + s[f[u][i - 1]][i - 1];
    for (int i = head[u]; i; i = nxt[i]) {
        int v = to[i];
        if (v == fa) continue;
        count(v, u);
    }
} 

inline bool cmp(const int &g, const int &h) {
    return dfn[g] < dfn[h];
}

int stk[N], tp, cl[N], tot; bool vis[N]; vector<int> son[N];

int Lca(int x, int y) {
    if (dep[x] < dep[y]) swap(x, y);
    for (int i = 18; i >= 0; i--) if (dep[f[x][i]] >= dep[y]) x = f[x][i];
    if (x == y) return x;
    for (int i = 18; i >= 0; i--) if (f[x][i] != f[y][i]) x = f[x][i], y = f[y][i];
    return f[x][0];
}

void ins(int x) {
    if (tp <= 1) return cl[++tot] = stk[++tp] = x, void();
    int lca = Lca(x, stk[tp]);
    if (lca != stk[tp]) {
        while (tp > 1 && dfn[lca] <= dfn[stk[tp - 1]]) son[stk[tp - 1]].push_back(stk[tp]), tp--;
        if (lca != stk[tp]) son[lca].push_back(stk[tp]), cl[++tot] = stk[tp] = lca;
    }
    cl[++tot] = stk[++tp] = x;
}

int up[N], upid[N];

void pre(int u) {
    //cout << u << " ";
    if (vis[u]) up[u] = 0, upid[u] = u;
    else up[u] = 0x3f3f3f3f, upid[u] = 0x3f3f3f3f;
    for (int i = son[u].size() - 1; i >= 0; i--) {
        int v = son[u][i]; pre(v);
        if (up[u] > up[v] + dep[v] - dep[u] 
        || (up[u] == up[v] + dep[v] - dep[u] && upid[u] > upid[v])) 
            up[u] = up[v] + dep[v] - dep[u], upid[u] = upid[v];
    }
}

int Min[N], Minid[N];

void dp(int u) {
    if (vis[u]) Min[u] = 0, Minid[u] = u;
    int fi = Min[u], se = 0x3f3f3f3f, fiid = Minid[u], seid = 0x3f3f3f3f;
    if (vis[u]) fi = 0, fiid = u;
    for (int i = son[u].size() - 1; i >= 0; i--) {
        int v = son[u][i];
        if (fi > up[v] + dep[v] - dep[u]
        || (fi == up[v] + dep[v] - dep[u] && fiid > upid[v]))
            se = fi, seid = fiid, fi = up[v] + dep[v] - dep[u], fiid = upid[v];
        else if (se > up[v] + dep[v] - dep[u]
            || (se == up[v] + dep[v] - dep[u] && seid > upid[v])) 
                se = up[v] + dep[v] - dep[u], seid = upid[v];
    }
    Min[u] = fi, Minid[u] = fiid;
    for (int i = son[u].size() - 1; i >= 0; i--) {
        int v = son[u][i]; 
        if (up[v] + dep[v] - dep[u] == fi && upid[v] == fiid) Min[v] = se + dep[v] - dep[u], Minid[v] = seid;
        else Min[v] = fi + dep[v] - dep[u], Minid[v] = fiid;
        dp(v);
    }
}

int get(int u, int k) {
    int res = 0;
    for (int i = 18; i >= 0; i--) if (k >= (1 << i)) k -= (1 << i), res += s[u][i], u = f[u][i];
    return res;
}

void calc(int u) {
    int sum = sze[u];
    for (int i = son[u].size() - 1; i >= 0; i--) {
        int v = son[u][i]; calc(v);
        int k = dep[v] - dep[u] + Min[u] - Min[v];
        int now = get(v, (k & 1) ? (k >> 1) : ((k >> 1) - (Minid[u] < Minid[v])));
        sum -= (now + sze[v]), ans[Minid[v]] += now;
    }
    ans[Minid[u]] += sum;
}

int main() {
    n = read();
    for (int i = 1; i < n; i++) {
        int u = read(), v = read();
        add_edge(u, v), add_edge(v, u);
    }
    dfs(1, 0), count(1, 0);
    for (int T = read(); T; T--) {
        for (int i = 1; i <= tot; i++) son[cl[i]].clear();
        for (int i = 1; i <= m; i++) vis[id[i]] = false; 
        m = read();
        for (int i = 1; i <= m; i++) vis[Id[i] = id[i] = read()] = true, ans[Id[i]] = 0;
        sort(id + 1, id + m + 1, cmp);
        tot = tp = 0; if (id[1] != 1) cl[tot = 1] = stk[tp = 1] = 1;
        for (int i = 1; i <= m; i++) ins(id[i]);
        while (tp > 1) son[stk[tp - 1]].push_back(stk[tp]), tp--;
        Min[1] = Minid[1] = 0x3f3f3f3f, pre(1), dp(1);
        calc(1);
        for (int i = 1; i <= m; i++) write(ans[Id[i]],  );
        putchar(\n);
    } 
    return 0;
} 

 

省选前的数据结构和字符串训练合编

标签:gis   dep   getc   多源   pid   font   alc   hnoi   sdoi   

原文地址:https://www.cnblogs.com/Urushibara-Ruka/p/14455654.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!