zoukankan      html  css  js  c++  java
  • BZOJ 1036 树的统计Count 树链剖分模板题

    题目链接:

    https://www.lydsy.com/JudgeOnline/problem.php?id=1036

    题目大意:

    一棵树上有n个节点,编号分别为1到n,每个节点都有一个权值w。我们将以下面的形式来要求你对这棵树完成
    一些操作:

    I. CHANGE u t : 把结点u的权值改为t

    II. QMAX u v: 询问从点u到点v的路径上的节点的最大权值 I
    II. QSUM u v: 询问从点u到点v的路径上的节点的权值和 注意:从点u到点v的路径上的节点包括u和v本身

    思路:

    树链剖分。

    一直没看树链剖分,刚刚看了一下,发现不难,两个dfs预处理出轻重链,然后用线段树维护即可。

    查询的时候用LCA查询。时间复杂度为两个log

    推荐博文:https://www.cnblogs.com/George1994/p/7821357.html

    模板:

     1 struct edge
     2 {
     3     int next;//指向下一个节点
     4     int u, v, w;
     5 };
     6 edge e[maxn];
     7 int head[maxn], node;//node记录节点的数目,head[i]记录连接着i的第一条边
     8 void addedge(int u, int v)
     9 {
    10     e[node].u = u;
    11     e[node].v = v;
    12     //e[node].w = w;
    13     e[node].next = head[u];
    14     head[u] = node++;
    15     e[node].u = v;
    16     e[node].v = u;
    17     //e[node].w = w;
    18     e[node].next = head[v];
    19     head[v] = node++;
    20 }
    21 int siz[maxn];//以u为根节点的子树的结点个数
    22 int top[maxn];//节点u所在链的顶端节点
    23 int son[maxn];//节点u重儿子
    24 int dep[maxn];//节点u的深度
    25 int faz[maxn];//节点u的父节点
    26 int tid[maxn];//节点u的dfs编号
    27 int rnk[maxn];//rnk[i]表示dfs编号为i的原始编号
    28 int cnt;//dfs序号
    29 void init()
    30 {
    31     memset(head, -1, sizeof(head));
    32     node = 0;
    33     Mem(siz);
    34     Mem(top);
    35     memset(son, -1, sizeof(son));
    36     Mem(dep);
    37     Mem(faz);
    38     Mem(tid);
    39     Mem(rnk);
    40     cnt = 0;
    41 }
    42 void dfs1(int u, int father, int depth)
    43 {
    44     // u当前节点 father 父节点 depth深度
    45     dep[u] = depth;
    46     faz[u] = father;
    47     siz[u] = 1;
    48     for(int i = head[u]; i != -1; i = e[i].next)
    49     {
    50         int v = e[i].v;
    51         if(v != faz[u])
    52         {
    53             dfs1(v, u, depth + 1);
    54             siz[u] += siz[v];//更新子树节点数目
    55             if(son[u] == -1 || siz[v] > siz[son[u]])
    56                 son[u] = v;//更新重儿子
    57         }
    58     }
    59 }
    60 void dfs2(int u, int t)
    61 {
    62     //u当前节点 t起始的重节点
    63     top[u] = t;
    64     tid[u] = ++cnt;
    65     rnk[cnt] = u;
    66     if(son[u] == -1)return;//不在重链上
    67     dfs2(son[u], t);//将这条重链上的所有点设置成起始的重节点
    68     for(int i = head[u]; i != -1; i = e[i].next)
    69     {
    70         int v = e[i].v;
    71         if(v != son[u] && v != faz[u])
    72         {
    73             dfs2(v, v);//v不是u的重儿子 也不是u的父节点 将v的top设置成自己 进一步递归
    74         }
    75     }
    76 }

    LCA的方法来查询:

     1 int solve_sum(int x, int y)//LCA top加速
     2 {
     3     int ans = 0;
     4     int fx = top[x], fy = top[y];
     5     while(fx != fy)
     6     {
     7         if(dep[fx] >= dep[fy])
     8         {
     9             //计算x到其链的起点的路径和
    10             ans += query_sum(1, tid[fx], tid[x]);
    11             //将x设置成起始节点的父节点,走轻边,继续循环
    12             x = faz[fx];
    13         }
    14         else
    15         {
    16             ans += query_sum(1, tid[fy], tid[y]);
    17             y = faz[fy];
    18         }
    19         fx = top[x], fy = top[y];
    20     }
    21     //此时x和y在同一条重链上
    22     if(tid[x] <= tid[y])ans += query_sum(1, tid[x], tid[y]);
    23     else ans += query_sum(1, tid[y], tid[x]);
    24     return ans;
    25 }

    题目完整代码:

      1 #include<bits/stdc++.h>
      2 #define IOS ios::sync_with_stdio(false);//不可再使用scanf printf
      3 #define Max(a, b) ((a) > (b) ? (a) : (b))//禁用于函数,会超时
      4 #define Min(a, b) ((a) < (b) ? (a) : (b))
      5 #define Mem(a) memset(a, 0, sizeof(a))
      6 #define Dis(x, y, x1, y1) ((x - x1) * (x - x1) + (y - y1) * (y - y1))
      7 #define MID(l, r) ((l) + ((r) - (l)) / 2)
      8 #define lson ((o)<<1)
      9 #define rson ((o)<<1|1)
     10 #pragma comment(linker, "/STACK:102400000,102400000")//栈外挂
     11 using namespace std;
     12 inline int read()
     13 {
     14     int x=0,f=1;char ch=getchar();
     15     while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();}
     16     while (ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
     17     return x*f;
     18 }
     19 
     20 typedef long long ll;
     21 const int maxn = 200000 + 10;
     22 const int mod = 1000000007;//const引用更快,宏定义也更快
     23 const int INF = 1e9;
     24 
     25 struct edge
     26 {
     27     int next;//指向下一个节点
     28     int u, v, w;
     29 };
     30 edge e[maxn];
     31 int head[maxn], node;//node记录节点的数目,head[i]记录连接着i的第一条边
     32 void addedge(int u, int v)
     33 {
     34     e[node].u = u;
     35     e[node].v = v;
     36     //e[node].w = w;
     37     e[node].next = head[u];
     38     head[u] = node++;
     39     e[node].u = v;
     40     e[node].v = u;
     41     //e[node].w = w;
     42     e[node].next = head[v];
     43     head[v] = node++;
     44 }
     45 int siz[maxn];//以u为根节点的子树的结点个数
     46 int top[maxn];//节点u所在链的顶端节点
     47 int son[maxn];//节点u重儿子
     48 int dep[maxn];//节点u的深度
     49 int faz[maxn];//节点u的父节点
     50 int tid[maxn];//节点u的dfs编号
     51 int rnk[maxn];//rnk[i]表示dfs编号为i的原始编号
     52 int cnt;//dfs序号
     53 void init()
     54 {
     55     memset(head, -1, sizeof(head));
     56     node = 0;
     57     Mem(siz);
     58     Mem(top);
     59     memset(son, -1, sizeof(son));
     60     Mem(dep);
     61     Mem(faz);
     62     Mem(tid);
     63     Mem(rnk);
     64     cnt = 0;
     65 }
     66 void dfs1(int u, int father, int depth)
     67 {
     68     // u当前节点 father 父节点 depth深度
     69     dep[u] = depth;
     70     faz[u] = father;
     71     siz[u] = 1;
     72     for(int i = head[u]; i != -1; i = e[i].next)
     73     {
     74         int v = e[i].v;
     75         if(v != faz[u])
     76         {
     77             dfs1(v, u, depth + 1);
     78             siz[u] += siz[v];//更新子树节点数目
     79             if(son[u] == -1 || siz[v] > siz[son[u]])
     80                 son[u] = v;//更新重儿子
     81         }
     82     }
     83 }
     84 void dfs2(int u, int t)
     85 {
     86     //u当前节点 t起始的重节点
     87     top[u] = t;
     88     tid[u] = ++cnt;
     89     rnk[cnt] = u;
     90     if(son[u] == -1)return;//不在重链上
     91     dfs2(son[u], t);//将这条重链上的所有点设置成起始的重节点
     92     for(int i = head[u]; i != -1; i = e[i].next)
     93     {
     94         int v = e[i].v;
     95         if(v != son[u] && v != faz[u])
     96         {
     97             dfs2(v, v);//v不是u的重儿子 也不是u的父节点 将v的top设置成自己 进一步递归
     98         }
     99     }
    100 }
    101 struct node{
    102     int l, r, x, sum;
    103 }tree[maxn];
    104 int value[maxn];
    105 void build(int o, int l, int r)
    106 {
    107     tree[o].l = l, tree[o].r = r;
    108     if(l == r)
    109     {
    110         tree[o].x = tree[o].sum = value[rnk[l]];//rnk[i]表示dfs编号为i,原始编号为rnk[i]
    111         return;
    112     }
    113     int m = MID(l, r);
    114     build(lson, l, m);
    115     build(rson, m + 1, r);
    116     tree[o].sum = tree[lson].sum + tree[rson].sum;
    117     tree[o].x = Max(tree[lson].x, tree[rson].x);
    118 }
    119 void update(int o, int p, int v)
    120 {
    121     if(tree[o].l == tree[o].r){tree[o].sum = tree[o].x = v;return;}
    122     if(p <= tree[lson].r)update(lson, p, v);
    123     else update(rson, p, v);
    124     tree[o].sum = tree[lson].sum + tree[rson].sum;
    125     tree[o].x = Max(tree[lson].x, tree[rson].x);
    126 }
    127 int query_sum(int o, int ql, int qr)
    128 {
    129     if(ql <= tree[o].l && qr >= tree[o].r)return tree[o].sum;
    130     int ans = 0;
    131     if(ql <= tree[lson].r)ans += query_sum(lson, ql, qr);
    132     if(qr >= tree[rson].l)ans += query_sum(rson, ql, qr);
    133     return ans;
    134 }
    135 int query_max(int o, int ql, int qr)
    136 {
    137     //cout<<o<<endl;
    138     if(ql <= tree[o].l && qr >= tree[o].r)return tree[o].x;
    139     int ans = -INF, tmp;
    140     if(ql <= tree[lson].r)tmp = query_max(lson, ql, qr), ans = Max(ans, tmp);
    141     if(qr >= tree[rson].l)tmp = query_max(rson, ql, qr), ans = Max(ans, tmp);
    142     return ans;
    143 }
    144 int solve_sum(int x, int y)//LCA top加速
    145 {
    146     int ans = 0;
    147     int fx = top[x], fy = top[y];
    148     while(fx != fy)
    149     {
    150         if(dep[fx] >= dep[fy])
    151         {
    152             //计算x到其链的起点的路径和
    153             ans += query_sum(1, tid[fx], tid[x]);
    154             //将x设置成起始节点的父节点,走轻边,继续循环
    155             x = faz[fx];
    156         }
    157         else
    158         {
    159             ans += query_sum(1, tid[fy], tid[y]);
    160             y = faz[fy];
    161         }
    162         fx = top[x], fy = top[y];
    163     }
    164     //此时x和y在同一条重链上
    165     if(tid[x] <= tid[y])ans += query_sum(1, tid[x], tid[y]);
    166     else ans += query_sum(1, tid[y], tid[x]);
    167     return ans;
    168 }
    169 int solve_max(int x, int y)//LCA top加速
    170 {
    171     int ans = -INF, tmp;
    172     int fx = top[x], fy = top[y];
    173     while(fx != fy)
    174     {
    175         if(dep[fx] >= dep[fy])
    176         {
    177             //计算x到其链的起点的路径和
    178             tmp = query_max(1, tid[fx], tid[x]);
    179             //将x设置成起始节点的父节点,走轻边,继续循环
    180             x = faz[fx];
    181         }
    182         else
    183         {
    184             tmp = query_max(1, tid[fy], tid[y]);
    185             y = faz[fy];
    186         }
    187         ans = Max(ans, tmp);
    188         fx = top[x], fy = top[y];
    189     }
    190     //此时x和y在同一条重链上
    191     if(tid[x] <= tid[y])tmp = query_max(1, tid[x], tid[y]);
    192     else tmp = query_max(1, tid[y], tid[x]);
    193     ans = Max(ans, tmp);
    194     return ans;
    195 }
    196 
    197 int main()
    198 {
    199     init();
    200     int n, u, v;
    201     scanf("%d", &n);
    202     for(int i = 1; i < n; i++)
    203     {
    204         scanf("%d%d", &u, &v);
    205         addedge(u, v);
    206     }
    207     for(int i = 1; i <= n; i++)scanf("%d", &value[i]);
    208     dfs1(1, 0, 1);
    209     dfs2(1, 1);
    210     build(1, 1, n);
    211     int m, a, b;
    212     char s[10];
    213     scanf("%d", &m);
    214     while(m--)
    215     {
    216         scanf("%s%d%d", s, &a, &b);
    217         if(s[0] == 'C')update(1, tid[a], b);//更新的时候下标必须使用dfs编号的
    218         else if(s[1] == 'S')printf("%d
    ", solve_sum(a, b));
    219         else printf("%d
    ", solve_max(a, b));
    220     }
    221     return 0;
    222 }
  • 相关阅读:
    Spring依赖注入的方式、类型、Bean的作用域、自动注入、在Spring配置文件中引入属性文件
    RESTful风格、异常处理、Spring框架
    文件上传、数据校验(后台)、拦截器
    接收的参数为日期类型、controller控制层进行数据保存、进行重定向跳转
    SpringMVC入门Demo
    Mybatis入门Demo(单表的增删改查)
    Spring
    spring的exception
    restful风格
    Java后台验证
  • 原文地址:https://www.cnblogs.com/fzl194/p/9623986.html
Copyright © 2011-2022 走看看