zoukankan      html  css  js  c++  java
  • 洛谷P3384 【模板】轻重链剖分

    题目描述

    如题,已知一棵包含 NNN 个结点的树(连通且无环),每个节点上包含一个数值,需要支持以下操作:

    操作 111: 格式: 1 x y z1 x y z1 x y z 表示将树从 xxx 到 yyy 结点最短路径上所有节点的值都加上 zzz。

    操作 222: 格式: 2 x y2 x y2 x y 表示求树从 xxx 到 yyy 结点最短路径上所有节点的值之和。

    操作 333: 格式: 3 x z3 x z3 x z 表示将以 xxx 为根节点的子树内所有节点值都加上 zzz。

    操作 444: 格式: 4 x4 x4 x 表示求以 xxx 为根节点的子树内所有节点值之和

    输入格式

    第一行包含 444 个正整数 N,M,R,PN,M,R,PN,M,R,P,分别表示树的结点个数、操作个数、根节点序号和取模数(即所有的输出结果均对此取模)。

    接下来一行包含 NNN 个非负整数,分别依次表示各个节点上初始的数值。

    接下来 N−1N-1N1 行每行包含两个整数 x,yx,yx,y,表示点 xxx 和点 yyy 之间连有一条边(保证无环且连通)。

    接下来 MMM 行每行包含若干个正整数,每行表示一个操作,格式如下:

    操作 111: 1 x y z1 x y z1 x y z;

    操作 222: 2 x y2 x y2 x y;

    操作 333: 3 x z3 x z3 x z;

    操作 444: 4 x4 x4 x。

    输出格式

    输出包含若干行,分别依次表示每个操作 222 或操作 444 所得的结果(PPP 取模)。

    输入输出样例

    输入 #1
    5 5 2 24
    7 3 7 8 0 
    1 2
    1 5
    3 1
    4 1
    3 4 2
    3 2 2
    4 5
    1 5 1 3
    2 1 3
    输出 #1
    2
    21
    人家讲的比我好,就不写题解了T^T https://www.luogu.com.cn/problem/solution/P3384
    需要注意的点都在注释
    #include <bits/stdc++.h>
    #define N 100005
    using namespace std;
    int size[N], son[N], top[N], dep[N], fa[N], dfn[N], wt[N], head[N], ver[N * 2], Next[N * 2], w[N], n, m, r, mod, tot, cnt = 0;
    void add(int x, int y)
    {
        ver[++tot] = y, Next[tot] = head[x], head[x] = tot;
    }
    /*----------下为线段树----------*/
    struct SegmentTree
    {
        int l;
        int r;
        int sum;
        int add;
    } t[4 * N];
    void build(int p, int l, int r)
    {
        t[p].l = l;
        t[p].r = r;
        if(l == r)
        {
            t[p].sum = wt[l];//无效模可能会超时? 
            if(t[p].sum >= mod) t[p].sum %= mod;
            return;
        }
        int mid = (l + r) >> 1;
        build(2 * p, l, mid);
        build(2 * p + 1, mid + 1, r);
        t[p].sum = (t[2 * p].sum + t[2 * p + 1].sum) % mod;
    }
    
    void spread(int p)
    {
        if(t[p].add)
        {
            t[2 * p].sum += t[p].add * (t[2 * p].r - t[2 * p].l + 1) % mod; 
            t[2 * p + 1].sum += t[p].add * (t[2 * p + 1].r - t[2 * p + 1].l + 1) % mod; 
            t[2 * p].add += t[p].add; 
            t[2 * p + 1].add += t[p].add; 
            t[p].add = 0;
        }
    }
    int ask(int p, int l, int r)
    {
        if(t[p].l >= l && t[p].r <= r)
        {
            return t[p].sum % mod;
        }
        spread(p);
        int mid = (t[p].l + t[p].r) >> 1;
        int val = 0;
        if(l <= mid) val = (val + ask(2 * p, l, r)) % mod;
        if(r > mid) val = (val + ask(2 * p + 1, l, r)) % mod;
        return val;
    }
    void change(int p, int l, int r, int d)
    {
        if(t[p].l >= l && t[p].r <= r)
        {
            t[p].sum = (t[p].sum + d * (t[p].r - t[p].l + 1) % mod) % mod;
            t[p].add += d;
            return; 
        }
        spread(p);
        int mid = (t[p].l + t[p].r) >> 1;
        if(l <= mid) change(2 * p, l, r, d);
        if(r > mid) change(2 * p + 1, l, r, d);
        t[p].sum = (t[2 * p].sum + t[2 * p + 1].sum) % mod;
    }
    /*----------下为树剖预处理----------*/
    void dfs1(int x, int f, int deep)//x为当前节点, f为父亲, deep为深度 
    {
        dep[x] = deep;
        fa[x] = f;
        size[x] = 1;//记录每个非叶子节点的子树大小(包括自己)
        for(int i = head[x]; i; i = Next[i])
        {
            int y = ver[i];
            if(y == f) continue;
            dfs1(y, x, deep + 1);
            size[x] += size[y];
            if(size[y] > size[son[x]]) son[x] = y;//更新重儿子 
        }
    }
    void dfs2(int x, int topf)//topf是当前链最顶端的节点 
    {
        dfn[x] = ++cnt;
        wt[cnt] = w[x];
        top[x] = topf;
        if(!son[x]) return;
        dfs2(son[x], topf);//保证重链连续性, 先搜索重儿子 
        for(int i = head[x]; i; i = Next[i]) 
        {
            int y = ver[i];
            if(y == fa[x] || y == son[x]) continue;
            dfs2(y, y);//对于每个轻儿子有一条从他自己开始的链 
        }
    }
    /*----------下为s树剖查询等----------*/
    inline int qRange(int x, int y)
    {
        int ans = 0;
        while(top[x] != top[y])//当两个点还没跳到同一条链上 
        {
            if(dep[top[x]] < dep[top[y]]) swap(x, y);
            ans = (ans + ask(1, dfn[top[x]], dfn[x])) % mod;
            x = fa[top[x]];
        }
        //直到两个点处于同一条链上
        if(dep[x] > dep[y]) swap(x, y);
        return (ans + ask(1, dfn[x], dfn[y])) % mod;
    }
    inline int qSon(int x)
    {
        return ask(1, dfn[x], dfn[x] + size[x] - 1);//子树也是连号的 
    }
    inline void updateRange(int x, int y, int k)
    {
        k %= mod;
        while(top[x] != top[y])//当两个点还没跳到同一条链上 
        {
            if(dep[top[x]] < dep[top[y]]) swap(x, y);
            change(1, dfn[top[x]], dfn[x], k);
            x = fa[top[x]];;
        }
        if(dep[x] > dep[y]) swap(x, y);
        change(1, dfn[x], dfn[y], k);
    }
    inline void updateSon(int x, int k)
    {
        change(1, dfn[x], dfn[x] + size[x] - 1, k);
    }
    int main()
    {
        cin >> n >> m >> r >> mod;
        int i;
        for(i = 1; i <= n; i++) scanf("%d", &w[i]);
        for(i = 1; i <= n - 1; i++)
        {
            int x, y;
            scanf("%d%d", &x, &y);
            add(x, y);
            add(y, x);
        }
        dfs1(r, 0, 1);//别忘先dfs后建树! 
        dfs2(r, r);
        build(1, 1, n);
        for(i = 1; i <= m; i++)
        {
            int op, x, y, z;
            scanf("%d", &op);
            if(op == 1)
            {
                scanf("%d%d%d", &x, &y, &z);
                updateRange(x, y, z);
            }
            else if(op == 2)
            {
                scanf("%d%d", &x, &y);
                cout << qRange(x, y) << endl;
            }
            else if(op == 3)
            {
                scanf("%d%d", &x, &z);
                updateSon(x, z);
            }
            else
            {
                scanf("%d", &x);
                cout << qSon(x) << endl;
            }
        }
        return 0;
    }
  • 相关阅读:
    zbb20180930 Postman 使用方法详解
    Cookie、Session、jsp、EL、JSTL
    Http协议、Tomcat、servlet
    xml、网络编程、 反射
    JDBC、DBUtils
    Java IO流对象、多线程
    mySql
    Java基础
    VueJs
    GIT
  • 原文地址:https://www.cnblogs.com/lipoicyclic/p/13283246.html
Copyright © 2011-2022 走看看