zoukankan      html  css  js  c++  java
  • 树链剖分模版

      1 #include <stdio.h>
      2 #include <cstring>
      3 #include <iostream>
      4 #include <string>
      5 #include <algorithm>
      6 #include <queue>
      7 #include <vector>
      8 #include <math.h>
      9 #include <map>
     10 
     11 #define LL long long
     12 using namespace std;
     13 const int maxn = 2e5 + 10;
     14 
     15 struct Edge{
     16     int to,next;
     17 }edge[maxn];
     18 
     19 int tot,head[maxn];
     20 
     21 void add_edge(int u,int v){
     22     edge[++tot] = Edge{v,head[u]};
     23     head[u] = tot;
     24 }
     25 
     26 int mod;
     27 int v[maxn]; // 结点权值
     28 int fa[maxn]; // 父亲
     29 int dep[maxn]; // 深度
     30 int siz[maxn]; // 大小
     31 int son[maxn]; // 重儿子
     32 
     33 // 第一遍的dfs可以得到深度,父亲,大小,重儿子
     34 void dfs1(int u,int f){ // u是当前结点,f是u的父亲
     35     fa[u] = f;
     36     dep[u] = dep[f] + 1;
     37     siz[u] = 1;
     38     int maxsize = -1;  // 判断是不是重儿子的一个临时变量
     39     for (int i=head[u];~i;i=edge[i].next){
     40         int v = edge[i].to;
     41         if (v == f)   //如果是父亲肯定不可以
     42             continue;
     43         dfs1(v,u);
     44         siz[u] += siz[v];
     45         if (siz[v] > maxsize){
     46             maxsize = siz[v];
     47             son[u] = v;  // u的重儿子就是v
     48         }
     49     }
     50 }
     51 
     52 int tim; // 时间戳计数器
     53 int dfn[maxn]; // 时间戳
     54 int top[maxn]; //重链的顶部
     55 int w[maxn]; // 结点权值dfs序
     56 
     57 void dfs2(int u,int t){ // u是当前结点,t是当前结点的重链的头
     58     dfn[u] = ++tim;
     59     top[u] = t;
     60     w[tim] = v[u];
     61     if (!son[u])  // 如果不存在重儿子,那么它就是叶子结点,退出
     62         return;
     63     dfs2(son[u],t);
     64     for (int i=head[u];~i;i=edge[i].next){
     65         int v = edge[i].to;
     66         if (v == fa[u] || v == son[u])   // 往上遍历肯定不可以了,因为前面的dfs2已经遍历了重儿子所以这里也没必要了
     67             continue;
     68         dfs2(v,v);   // 此时这个肯定是轻儿子
     69     }
     70 }
     71 
     72 struct segment_tree{
     73     int l,r,val;
     74     int lazy;
     75 }tree[maxn*4];
     76 
     77 void pushup(int nod){
     78     tree[nod].val = (tree[nod<<1].val + tree[(nod<<1)+1].val) % mod;
     79 }
     80 
     81 void pushdown(int nod){
     82     tree[nod<<1].lazy += tree[nod].lazy;
     83     tree[(nod<<1)+1].lazy += tree[nod].lazy;
     84     tree[nod<<1].val += (tree[nod<<1].r-tree[nod<<1].l + 1) * tree[nod].lazy % mod;
     85     tree[(nod<<1)+1].val += (tree[(nod<<1)+1].r-tree[(nod<<1)+1].l+1) * tree[nod].lazy % mod;
     86     tree[nod].lazy = 0;
     87 }
     88 
     89 void build(int l,int r,int nod=1){
     90     tree[nod].l = l;
     91     tree[nod].r = r;
     92     if (l == r){
     93         tree[nod].lazy = 0;
     94         tree[nod].val = w[l] % mod;
     95         return ;
     96     }
     97     int mid = (l+r)>>1;
     98     build(l,mid,nod<<1);
     99     build(mid+1,r,(nod<<1)+1);
    100     pushup(nod);
    101 }
    102 
    103 void modify(int x,int y,int z,int k=1){
    104     int l = tree[k].l, r = tree[k].r;
    105     if (x<= l && y>=r){
    106         tree[k].lazy += z;
    107         tree[k].val += (r-l+1) * z;
    108         tree[k].val %= mod;
    109         return ;
    110     }
    111     if (tree[k].lazy)
    112         pushdown(k);
    113     int mid = (l+r)>>1;
    114     if (x<=mid){
    115         modify(x,y,z,k<<1);
    116     }
    117     if (y>mid){
    118         modify(x,y,z,(k<<1)+1);
    119     }
    120     pushup(k);
    121 }
    122 
    123 int query(int x,int y,int k=1){
    124     int l = tree[k].l,r = tree[k].r;
    125     if (x<=l && y>=r){
    126         return tree[k].val;
    127     }
    128     if (tree[k].lazy){
    129         pushdown(k);
    130     }
    131     int sum = 0,mid = (l+r)>>1;
    132     if (x <= mid){
    133         sum += query(x,y,k<<1);
    134     }
    135     if (y > mid){
    136         sum += query(x,y,(k<<1)+1);
    137     }
    138     return sum % mod;
    139 }
    140 
    141 void mchain(int x,int y,int z){  // 结点x->结点y 最短路径上所有结点加z
    142     z %= mod;
    143     while (top[x] != top[y]){
    144         if (dep[top[x]] < dep[top[y]])
    145             swap(x,y);
    146         modify(dfn[top[x]],dfn[x],z);
    147         x = fa[top[x]];
    148     }
    149     if (dep[x] > dep[y])
    150         swap(x,y);
    151     modify(dfn[x],dfn[y],z);
    152 }
    153 
    154 int qchain(int x,int y){  // 查询x到y结点最短路径上所有节点的值之和
    155     int ret = 0;
    156     while (top[x] != top[y]){
    157         if (dep[top[x]] < dep[top[y]])
    158             swap(x,y);
    159         ret += query(dfn[top[x]],dfn[x]);
    160         x = fa[top[x]];
    161     }
    162     if (dep[x] > dep[y])
    163         swap(x,y);
    164     ret += query(dfn[x],dfn[y]);
    165     return ret % mod;
    166 }
    167 
    168 void mson(int x,int z){ // 以x为根节点的子树内所有节点值都加上z
    169     modify(dfn[x],dfn[x]+siz[x]-1,z);  // 必定是连续的
    170 }
    171 
    172 int qson(int x){  // 以x为根节点的子树内所有节点值之和
    173     return query(dfn[x],dfn[x]+siz[x]-1);
    174 }
    175 
    176 
    177 int main(){
    178     memset(head,-1, sizeof(head));
    179     int n,m,r;
    180     scanf("%d%d%d%d",&n,&m,&r,&mod);
    181     for (int i=1;i<=n;i++){
    182         scanf("%d",&v[i]);
    183     }
    184     for (int i=1;i<n;i++){
    185         int u,v;
    186         scanf("%d%d",&u,&v);
    187         add_edge(u,v);
    188         add_edge(v,u);
    189     }
    190     dfs1(r,r);
    191     dfs2(r,r);
    192     build(1,n);
    193     while (m--){
    194         int opt,x,y,z;
    195         scanf("%d",&opt);
    196         switch(opt){
    197             case 1:
    198                 scanf("%d%d%d",&x,&y,&z);
    199                 mchain(x,y,z);
    200                 break;
    201             case 2:
    202                 scanf("%d%d",&x,&y);
    203                 printf("%d
    ",qchain(x,y));
    204                 break;
    205             case 3:
    206                 scanf("%d%d",&x,&z);
    207                 mson(x,z);
    208                 break;
    209             case 4:
    210                 scanf("%d",&x);
    211                 printf("%d
    ",qson(x));
    212                 break;
    213         }
    214     }
    215     return 0;
    216 }
  • 相关阅读:
    Java面试之最常见的十道面试题(超经典)
    hdu 3939(勾股+容斥)
    poj 1845 (逆元 + 约数和)
    hdu 5607 BestCoder Round #68 (矩阵快速幂)
    中国剩余定理
    Math
    (⊙o⊙)…
    lucas定理
    hdu 5600 BestCoder Round #67 (div.2)
    hdu5601 BestCoder Round #67 (div.2)
  • 原文地址:https://www.cnblogs.com/-Ackerman/p/11457011.html
Copyright © 2011-2022 走看看