• 省选前的数据结构训练


    虚树

    [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('
    ');
    }
     
     
    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;
    }
    View Code

     

    「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('
    ');
        } 
        return 0;
    } 
    View Code

     

    「SDOI2017」天才黑客

    圆方树

    「SDOI2018」战略游戏

    建完圆方树,把圆点点权设$1$,方点设为$0$,点权存在点的父亲边上

    按$dfs$序每次询问的点排序,每对相邻的点求距离,然后加减其它几个多算没算的值

    #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 = 1e5 + 10, M = 2e5 + 10;
    
    int n, m, k, a[N], nodeid;
    
    int head[N], to[M << 1], nxt[M << 1], cnt;
    
    void add_edge(int u, int v) {
        to[++cnt] = v, nxt[cnt] = head[u], head[u] = cnt;
    }
    
    int dfn[N << 1], low[N], times, stk[N], tp;
    
    vector<int> son[N << 1]; int fa[N << 1][18], dep[N << 1], dis[N << 1];
    
    void tarjan(int u) {
        dfn[u] = low[u] = ++times, stk[++tp] = u;
        for (int i = head[u]; i; i = nxt[i]) {
            int v = to[i];
            if (!dfn[v]) {
                tarjan(v);
                if (low[u] > low[v]) low[u] = low[v];
                if (dfn[u] == low[v]) {
                    ++nodeid;
                    for (int p = 0; p != v; tp--) {
                        p = stk[tp];
                        son[nodeid].push_back(p);
                    }
                    son[u].push_back(nodeid);
                }
            }
            else if (low[u] > dfn[v]) low[u] = dfn[v];
        }
    }
    
    void dfs(int u) {
        dfn[u] = ++times;
        for (int i = 1; i <= 17; i++) fa[u][i] = fa[fa[u][i - 1]][i - 1];
        for (int i = son[u].size() - 1; i >= 0; i--) {
            int v = son[u][i]; 
            dep[v] = dep[u] + 1, fa[v][0] = u, dis[v] = dis[u] + (v <= n), dfs(v);
        }
    }
    
    int lca(int x, int y) {
        if (dep[x] < dep[y]) swap(x, y);
        for (int i = 17; i >= 0; i--) if (dep[fa[x][i]] >= dep[y]) x = fa[x][i];
        if (x == y) return x;
        for (int i = 17; i >= 0; i--) if (fa[x][i] != fa[y][i]) x = fa[x][i], y = fa[y][i];
        return fa[x][0];
    }
    
    inline bool cmp(const int &g, const int &h) {
        return dfn[g] < dfn[h];
    }
    
    int main() {
        for (int T = read(); T; T--) {
            n = read(), m = read(), cnt = 0;
            for (int i = 1; i <= n; i++) head[i] = 0, dfn[i] = low[i] = 0;
            for (int i = 1; i <= m; i++) {
                int u = read(), v = read();
                add_edge(u, v), add_edge(v, u);
            }
            for (int i = 1; i <= nodeid; i++) son[i].clear();
            nodeid = n, times = tp = 0, tarjan(1);
            times = 0, dfs(1);
            for (int q = read(); q; q--) {
                k = read();
                for (int i = 1; i <= k; i++) a[i] = read();
                sort(a + 1, a + k + 1, cmp);
                int ans = dis[a[1]] + dis[a[k]] - 2 * dis[lca(a[1], a[k])];
                for (int i = 2; i <= k; i++) ans += dis[a[i - 1]] + dis[a[i]] - 2 * dis[lca(a[i - 1], a[i])];
                ans = (ans >> 1) - k + (lca(a[1], a[k]) <= n);
                write(ans, '
    ');
            }
        }
        return 0;
    }
    View Code

     

    动态树

    LCT学习笔记

    树套树

    平衡树

    [CF702F]T-shirt

    先将T恤按品质从大到小排,品质相同按价格从小到大排

    暴力则是对于每个人,按顺序试遍每件T恤

    优化则考虑对于每件T恤,有哪些人会买

    具体是维护一个当前所有人所剩钱数组成的递增序列,二分出所剩钱数大于等于当前T恤的有哪些人(为该序列的一个后缀)

    直接将一段区间平移并不好直接做(但好像可以可持久化平衡树??还不是很懂哇)

    这题的平移只有向钱数少的方向平移

    假设当前T恤价格为$c_i$

    考虑把序列分为三段$[1,c_i),[c_i,2 imes c_i),[2 imes c_i, k]$,第二段暴力单点修改,第三段区间打上$-c_i$的$tag$

    发现每个人被暴力单点改的时候钱数会减少一半以上,最多被改$log$次

    #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 = 2e5 + 10;
    
    int n, k, nodeid, val[N], rd[N], cnt[N], ls[N], rs[N], rt, a, b, c, tag[N], g[N];
    
    struct shirt {
        int c, q;
        void readdata() {
            c = read(), q = read();
        }
        bool operator < (const shirt &g) const {
            if (q != g.q) return q > g.q;
            return c < g.c;
        }
    } t[N];
    
    int newnode(int s) {
        ++nodeid, rd[nodeid] = rand(), val[nodeid] = s;
        return nodeid;
    }
    
    void dec(int u, int s, int r) {
        tag[u] += s, val[u] -= s, g[u] += r, cnt[u] += r;
    }
    
    void pushdown(int u) {
        if (tag[u] || g[u]) {
            if (ls[u]) dec(ls[u], tag[u], g[u]);
            if (rs[u]) dec(rs[u], tag[u], g[u]);
            tag[u] = g[u] = 0;
        }
    }
    
    void split(int u, int s, int &x, int &y) {
        if (!u) return x = y = 0, void();
        pushdown(u);
        if (val[u] <= s) x = u, split(rs[u], s, rs[x], y);
        else y = u, split(ls[u], s, x, ls[y]);
    }
    
    int merge(int x, int y) {
        if (!x || !y) return x | y;
        if (rd[x] < rd[y]) return pushdown(x), rs[x] = merge(rs[x], y), x;
        else return pushdown(y), ls[y] = merge(x, ls[y]), y;
    }
    
    void dfs(int u) {
        pushdown(u);
        if (ls[u]) dfs(ls[u]);
        if (rs[u]) dfs(rs[u]);
        ls[u] = rs[u] = 0;
        int x, y; split(a, val[u], x, y), a = merge(merge(x, u), y);
    }
    
    void calc(int u) {
        pushdown(u);
        if (ls[u]) calc(ls[u]);
        if (rs[u]) calc(rs[u]);
    }
    
    int main() {
        n = read();
        for (int i = 1; i <= n; i++) t[i].readdata();
        sort(t + 1, t + n + 1);
        k = read(), rt = newnode(read());
        for (int i = 2; i <= k; i++) {
            int s = read();
            split(rt, s, a, b), rt = merge(merge(a, newnode(s)), b);
        }
        for (int i = 1; i <= n; i++) {
            split(rt, t[i].c - 1, a, b), dec(b, t[i].c, 1), split(b, t[i].c, b, c);
            dfs(b), rt = merge(a, c);
        }
        calc(rt);
        for (int i = 1; i <= k; i++) write(cnt[i], ' ');
        return 0;
    } 
    View Code

    CDQ分治&整体二分

    「YNOI2016」镜中的昆虫

     

    K-D tree

    珂朵莉树

    [CF896C]Willem, Chtholly and Seniorious

    #include <bits/stdc++.h>
    
    using namespace std;
    
    typedef long long ll;
    
    inline void write(ll 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);
    }
    
    inline ll fpow(ll x, ll y, ll Mod) {
        ll res = 1; x %= Mod;
        while (y) {
            if (y & 1) res = res * x % Mod;
            x = x * x % Mod;
            y >>= 1;
        }
        return res;
    }
    
    const int N = 1e5 + 10;
    
    int n, m, seed, vmax, tot;
    
    int rnd() {
        int ret = seed;
        seed = (seed * 7ll + 13) % 1000000007;
        return ret;
    }
    
    struct range {
        int l, r; mutable ll v;
        bool operator < (const range &g) const {
            return l < g.l;
        }
    } tmp[N];
    
    inline bool cmp(const range &g, const range &h) {
        return g.v < h.v;
    }
    
    set<range> odt;
    
    set<range>::iterator split(int x) {
        if (x > n) return odt.end();
        set<range>::iterator it = --odt.upper_bound(range{x, 0, 0});
        if (it->l == x) return it;
        int l = it->l, r = it->r; ll v = it->v;
        odt.erase(it), odt.insert(range{l, x - 1, v});
        return odt.insert(range{x, r, v}).first;
    }
    
    void assign(int l, int r, ll v) {
        set<range>::iterator itr = split(r + 1), itl = split(l);
        odt.erase(itl, itr), odt.insert(range{l, r, v});
    }
    
    int main() {
        cin >> n >> m >> seed >> vmax;
        for (int i = 1; i <= n; i++) odt.insert(range{i, i, rnd() % vmax + 1});
        //cout << endl;
        for (int i = 1; i <= m; i++) {
            int op = rnd() % 4 + 1, l = rnd() % n + 1, r = rnd() % n + 1, x, y = 0;
            if (l > r) swap(l, r);
            if (op == 3) x = rnd() % (r - l + 1) + 1;
            else x = rnd() % vmax + 1;
            if (op == 4) y = rnd() % vmax + 1;
            //cout << op << ' ' << l << " " << r << " " << x << " " << y << endl;
            if (op == 1) {
                set<range>::iterator itr = split(r + 1), itl = split(l);
                while (itl != itr) itl->v += x, itl++;
            }
            else if (op == 2) assign(l, r, x);
            else if (op == 3) {
                set<range>::iterator itr = split(r + 1), itl = split(l);
                tot = 0;
                while (itl != itr) tmp[++tot] = (*itl), itl++;
                sort(tmp + 1, tmp + tot + 1, cmp);
                for (int i = 1; i <= tot; i++) {
                    x -= (tmp[i].r - tmp[i].l + 1);
                    if (x <= 0) {
                        write(tmp[i].v, '
    ');
                        break;
                    }
                }
            }
            else {
                set<range>::iterator itr = split(r + 1), itl = split(l);
                int ans = 0;
                while (itl != itr) ans = (ans + fpow(itl->v, x, y) * (itl->r - itl->l + 1)) % y, itl++;
                write(ans, '
    ');
            }
        }
        return 0;
    }
    View Code

    线段树合并

    「NOI2020」命运

    #include <bits/stdc++.h>
    
    #define Mod 998244353
    
    using namespace std;
    
    typedef long long ll;
    
    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;
    }
    
    const int N = 5e5 + 10;
    
    int n, m, dep[N], g[N]; ll a, b;
    
    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;
    }
    
    void dfs(int u, int fa) {
        dep[u] = dep[fa] + 1;
        for (int i = head[u]; i; i = nxt[i]) {
            int v = to[i];
            if (v == fa) continue;
            dfs(v, u);
        }
    }
    
    int ls[N << 5], rs[N << 5], sum[N << 5], mul[N << 5], rt[N], nodeid;
    
    void pushdown(int u) {
        if (ls[u]) {
            sum[ls[u]] = 1ll * sum[ls[u]] * mul[u] % Mod;
            mul[ls[u]] = 1ll * mul[ls[u]] * mul[u] % Mod;
        }
        if (rs[u]) {
            sum[rs[u]] = 1ll * sum[rs[u]] * mul[u] % Mod;
            mul[rs[u]] = 1ll * mul[rs[u]] * mul[u] % Mod;
        }
        mul[u] = 1;
    }
    
    void modify(int &u, int l, int r, int pos) {
        u = ++nodeid, mul[u] = sum[u] = 1;
        if (l == r) return ;
        int mid = (l + r) >> 1;
        if (pos <= mid) modify(ls[u], l, mid, pos);
        else modify(rs[u], mid + 1, r, pos);
    }
    
    int query(int u, int l, int r, int Right) {
        if (r <= Right) return sum[u];
        pushdown(u);
        int mid = (l + r) >> 1, res = 0;
        res += query(ls[u], l, mid, Right); if (res >= Mod) res -= Mod;
        if (mid < Right && rs[u]) {
            res += query(rs[u], mid + 1, r, Right);
            if (res >= Mod) res -= Mod;
        }
        return res;
    }
    
    int merge(int x, int y, int l, int r) {
        if (!x && !y) return 0;
        if (!x) {
            a += sum[y]; if (a >= Mod) a -= Mod;
            mul[y] = 1ll * mul[y] * b % Mod, sum[y] = 1ll * sum[y] * b % Mod;
            return y;
        }
        if (!y) {
            b += sum[x]; if (b >= Mod) b -= Mod;
            mul[x] = 1ll * mul[x] * a % Mod, sum[x] = 1ll * sum[x] * a % Mod;
            return x;
        }
        if (l == r) {
            ll p = sum[x], q = sum[y]; 
            a += q; if (a >= Mod) a -= Mod;
            sum[x] = (sum[x] * a + sum[y] * b) % Mod;
            b += p; if (b >= Mod) b -= Mod;
            return x;
        }
        pushdown(x), pushdown(y);
        int mid = (l + r) >> 1;
        ls[x] = merge(ls[x], ls[y], l, mid);
        rs[x] = merge(rs[x], rs[y], mid + 1, r);
        sum[x] = sum[ls[x]] + sum[rs[x]]; if (sum[x] >= Mod) sum[x] -= Mod;
        return x;
    }
    
    void calc(int u, int fa) {
        modify(rt[u], 0, n, g[u]);
        for (int i = head[u]; i; i = nxt[i]) {
            int v = to[i];
            if (v == fa) continue;
            calc(v, u);
            a = query(rt[v], 0, n, dep[u]), b = 0;
            rt[u] = merge(rt[u], rt[v], 0, n);
        }
    }
    
    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);
        m = read();
        for (int i = 1; i <= m; i++) {
            int u = read(), v = read();
            if (g[v] < dep[u]) g[v] = dep[u];
        }
        calc(1, 0);
        cout << query(rt[1], 0, n, 0) << endl;
        return 0;
    }
    View Code

    「PKUWC2018」Minimax

    长链剖分

    [POI2014]HOT-Hotels 加强版

    #include <bits/stdc++.h>
    
    using namespace std;
    
    typedef long long ll;
    
    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;
    }
    
    const int N = 1e5 + 10;
    
    int n, 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 len[N], hea[N];
    
    void dfs(int u, int fa) {
        for (int i = head[u]; i; i = nxt[i]) {
            int v = to[i];
            if (v == fa) continue;
            dfs(v, u);
            if (len[hea[u]] < len[v]) hea[u] = v;
        }
        len[u] = len[hea[u]] + 1;
    }
    
    ll tmp[N * 3], *id = tmp, *f[N], *g[N], ans;
    
    void calc(int u, int fa) {
        if (hea[u]) f[hea[u]] = f[u] + 1, g[hea[u]] = g[u] - 1, calc(hea[u], u);
        f[u][0] = 1, ans += g[u][0];
        for (int i = head[u]; i; i = nxt[i]) {
            int v = to[i];
            if (v == fa || v == hea[u]) continue;
            f[v] = id, id += len[v];
            id += len[v], g[v] = id, id += len[v];
            calc(v, u);
            for (int j = 0; j < len[v]; j++) {
                ans += f[v][j] * g[u][j + 1];
                if (j) ans += g[v][j] * f[u][j - 1];
            }
            for (int j = 0; j < len[v]; j++) {
                g[u][j + 1] += f[u][j + 1] * f[v][j];
                if (j) g[u][j - 1] += g[v][j];
                f[u][j + 1] += f[v][j];
            }
        }
    }
    
    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);
        f[1] = id, id += len[1];
        id += len[1], g[1] = id, id += len[1];
        calc(1, 0);
        cout << ans << endl;
        return 0;
    }
    View Code
  • 相关阅读:
    深入防火墙记录(2) java程序员
    今天装了Redhat Enterprise Linux 5.0 ,体验一下不同的感受. java程序员
    最小生成树
    UVA400 Unix ls
    sudt2404Super Prime
    sdut2143图结构练习——最短路径
    多校联赛(1)Saving Princess claire_
    树结构练习——排序二叉树的中序遍历
    hdu1042N!
    最短路径
  • 原文地址:https://www.cnblogs.com/Urushibara-Ruka/p/14455654.html
Copyright © 2020-2023  润新知