zoukankan      html  css  js  c++  java
  • [模板]洛谷T3384 树链剖分

    树剖是干什么的?

    考虑这样的情况:有一棵树,现在要对其进行路径(两节点间)操作、子树操作,例如将路径上(子树上)的所有节点全部加上一个值、求和等等。

    直接暴力操作固然是可行的,但时间肯定是个问题。

    这时我们想,如果能用数据结构维护树上节点就好了,但是树的“张牙舞爪”的样子,使得这个操作难以完成。

    于是,树剖应运而生。树剖的作用是,把树拆分成若干条“链”,显然,“链”是线性的,方便用数据结构维护。

    具体的拆分方式名为“轻重链剖分”。使用这种拆分方式,可以使任一节点到根的路径上,经过的重链和轻边数量均不超过logn,这里的n指的是树的节点总数。关于具体概念及复杂度证明请自行百度,此处不再赘述。

    树剖过程需要求得的一系列数组如下:

    fa[]:节点的父亲节点(根节点为无);

    dep[]:节点深度;

    size[]:以节点为根的子树的节点总数;

    son[]:节点的重儿子编号;

    top[]:节点所处重链的顶端节点;

    dfsx[]:按照重链优先遍历出的DFS序;

    pos[]:节点在数据结构中的位置。

    初始化过程:

    1.存图;

    2.进行第一遍DFS,自根向下遍历(这个过程类似于无根树转有根树),求出fa[]、dep[]、size[]、son[];

    3.进行第二遍DFS,按照重链优先的顺序遍历,求出top[]、dfsx[],这时的DFS序满足:同一条重链或同一棵子树上的节点在DFS序中是连续的;

    4.根据DFS序计算pos[],细节请见代码,我把这个过程叫做“反向映射”;

    5.按照DFS序,将节点值存入数据结构(我用的是线段树)。

    查询及修改:

    1.路径操作,需要知道两节点的LCA,但是不必单独去求,只需按照重链和轻边向上跳即可到达LCA(轻边跳一下,重链跳到top的父节点,话说我也不明白这样搞为什么是对的),沿路修改/查询即可,复杂度log^2n,细节请见代码。

    2.子树操作,因为同一棵子树上的节点在数据结构中是连续的,所以借助size值,仅修改/查询一次即可,复杂度logn。

    最后提醒一句,适当取模,取少了计算结果会溢出,取多了会TLE。。。

    代码如下:

      1 #include<cstdio>
      2 #include<iostream>
      3 #include<cstring>
      4 #include<cmath>
      5 #include<ctime>
      6 #include<cstdlib>
      7 
      8 #include<string>
      9 #include<stack>
     10 #include<queue>
     11 #include<vector>
     12 #include<algorithm>
     13 #include<map>
     14 #include<set>
     15 
     16 #define ll long long
     17 
     18 using namespace std;
     19 
     20 inline void readint(int &x){
     21     x=0;
     22     char t=getchar();
     23     bool f=0;
     24     
     25     while(t<'0' || t>'9'){
     26         if(t=='-')f=1;
     27         t=getchar();
     28     }
     29     
     30     while(t>='0' && t<='9'){
     31         x=(x<<3)+(x<<1)+t-'0';
     32         t=getchar();
     33     }
     34     
     35     if(f)x=-x;
     36 }
     37 
     38 inline void readll(ll &x){
     39     x=0;
     40     char t=getchar();
     41     bool f=0;
     42     
     43     while(t<'0' || t>'9'){
     44         if(t=='-')f=1;
     45         t=getchar();
     46     }
     47     
     48     while(t>='0' && t<='9'){
     49         x=(x<<3)+(x<<1)+t-'0';
     50         t=getchar();
     51     }
     52     
     53     if(f)x=-x;
     54 }
     55 
     56 ll a[200010];  //点值 
     57 
     58 int v[200010];
     59 int first[200010];   
     60 int next[200010];
     61 int ord=0;  //邻接表 
     62 
     63 int fa[200010];
     64 int dep[200010];
     65 int size[200010];
     66 int son[200010];
     67 
     68 int top[200010];
     69 int dfsx[200010];
     70 int xu=0;
     71 
     72 int pos[200010];
     73 
     74 int n,m,root,mod,i;
     75 int f,x,y;
     76 ll k;
     77 
     78 inline void setup(){
     79     memset(first,0,sizeof(first));
     80     memset(next,0,sizeof(next));
     81     
     82     memset(son,0,sizeof(son));
     83 }
     84 
     85 inline void addedge(){
     86     ord++;
     87     v[ord]=y;
     88     next[ord]=first[x];
     89     first[x]=ord;
     90     
     91     ord++;
     92     v[ord]=x;
     93     next[ord]=first[y];
     94     first[y]=ord;
     95 }
     96 
     97 void dfs1(int);
     98 void dfs2(int);
     99 
    100 inline void path_update(int,int);
    101 inline ll path_query(int,int);
    102 inline void son_update(int);
    103 inline ll son_query(int);
    104 
    105 struct sgt{
    106     ll sum[800010];
    107     ll addv[800010];
    108     
    109     void build(int o,int l,int r){
    110         addv[o]=0;
    111         
    112         if(l==r)sum[o]=a[dfsx[l]];
    113         else{
    114             int mid=(l+r)>>1;
    115             int lson=o<<1;
    116             int rson=lson|1;
    117             
    118             build(lson,l,mid);
    119             build(rson,mid+1,r);
    120             
    121             sum[o]=(sum[lson]+sum[rson])%mod;
    122         }
    123     }
    124     
    125     void pushdown(int o,int l,int r,int mid,int lson,int rson){
    126         addv[lson]=(addv[lson]+addv[o])%mod;
    127         addv[rson]=(addv[rson]+addv[o])%mod;
    128         
    129         sum[lson]=(sum[lson]+addv[o]*(mid-l+1))%mod;
    130         sum[rson]=(sum[rson]+addv[o]*(r-mid))%mod;
    131         
    132         addv[o]=0;
    133     }
    134     
    135     void update(int o,int l,int r,int a,int b,int x){
    136         if(l>=a && r<=b){
    137             addv[o]=(addv[o]+x)%mod;
    138             sum[o]=(sum[o]+x*(r-l+1))%mod;
    139             return;
    140         }
    141         else{
    142             int mid=(l+r)>>1;
    143             int lson=o<<1;
    144             int rson=lson|1;
    145             
    146             if(addv[o])pushdown(o,l,r,mid,lson,rson);
    147             
    148             if(a<=mid)update(lson,l,mid,a,b,x);
    149             if(b>mid)update(rson,mid+1,r,a,b,x);
    150             
    151             sum[o]=(sum[lson]+sum[rson])%mod;
    152         }
    153     }
    154     
    155     ll query(int o,int l,int r,int a,int b){
    156         if(l>=a && r<=b)return sum[o];
    157         else{
    158             int mid=(l+r)>>1;
    159             int lson=o<<1;
    160             int rson=lson|1;
    161             ll ans=0;
    162             
    163             if(addv[o])pushdown(o,l,r,mid,lson,rson);
    164             
    165             if(a<=mid)ans+=query(lson,l,mid,a,b);
    166             if(b>mid)ans=(ans+query(rson,mid+1,r,a,b))%mod;
    167             
    168             return ans;
    169         }
    170     }
    171 } tree;
    172 
    173 int main(){
    174     setup();
    175     
    176     readint(n);readint(m);readint(root);readint(mod);
    177     
    178     for(register int i=1;i<=n;i++)readll(a[i]);
    179     
    180     for(register int i=1;i<n;i++){
    181         readint(x);readint(y);
    182         addedge();
    183     }
    184     
    185     fa[root]=0;
    186     dep[root]=1;
    187     dfs1(root);
    188     
    189     top[root]=root;
    190     dfs2(root);
    191     
    192     for(register int i=1;i<=n;i++)pos[dfsx[i]]=i;
    193     
    194     tree.build(1,1,n);
    195     
    196     while(m--){
    197         readint(f);
    198         
    199         switch(f){
    200             case 1:{
    201                 readint(x);readint(y);readll(k);
    202                 path_update(x,y);
    203                 break;
    204             }
    205             case 2:{
    206                 readint(x);readint(y);
    207                 printf("%lld
    ",path_query(x,y));
    208                 break;
    209             }
    210             case 3:{
    211                 readint(x);readll(k);
    212                 son_update(x);
    213                 break;
    214             }
    215             case 4:{
    216                 readint(x);
    217                 printf("%lld
    ",son_query(x));
    218                 break;
    219             }
    220         }
    221     }
    222     
    223     return 0;
    224 }
    225 
    226 void dfs1(int x){  //fa,dep在上层处理 
    227     size[x]=1;
    228     int e=first[x],u=v[e],maxson=0;
    229     
    230     while(e){
    231         if(u==fa[x]){
    232             e=next[e];
    233             u=v[e];
    234             continue;
    235         }
    236         
    237         fa[u]=x;
    238         dep[u]=dep[x]+1;
    239         
    240         dfs1(u);
    241         
    242         size[x]+=size[u];
    243         if(size[u]>maxson){
    244             maxson=size[u];
    245             son[x]=u;
    246         }
    247         
    248         e=next[e];
    249         u=v[e];
    250     }
    251 }
    252 
    253 void dfs2(int x){  //top在上层处理 
    254     xu++;
    255     dfsx[xu]=x;
    256     
    257     if(son[x]){
    258         top[son[x]]=top[x];
    259         dfs2(son[x]);
    260     }
    261     
    262     int e=first[x],u=v[e];
    263     
    264     while(e){
    265         if(u==fa[x] || u==son[x]){
    266             e=next[e];
    267             u=v[e];
    268             continue;
    269         }
    270         
    271         top[u]=u;
    272         dfs2(u);
    273         
    274         e=next[e];
    275         u=v[e];
    276     }
    277 }
    278 
    279 inline void path_update(int x,int y){
    280     int tx=top[x],ty=top[y];
    281     
    282     while(tx!=ty){
    283         if(dep[tx]>dep[ty]){
    284             tree.update(1,1,n,pos[tx],pos[x],k);
    285             x=fa[tx];
    286             tx=top[x];
    287         }
    288         else{
    289             tree.update(1,1,n,pos[ty],pos[y],k);
    290             y=fa[ty];
    291             ty=top[y];
    292         }
    293     }
    294     
    295     if(pos[x]<pos[y])tree.update(1,1,n,pos[x],pos[y],k);
    296     else tree.update(1,1,n,pos[y],pos[x],k);
    297 }
    298 
    299 inline ll path_query(int x,int y){
    300     ll ans=0;
    301     int tx=top[x],ty=top[y];
    302     
    303     while(tx!=ty){
    304         if(dep[tx]>dep[ty]){
    305             ans+=tree.query(1,1,n,pos[tx],pos[x]);
    306             x=fa[tx];
    307             tx=top[x];
    308         }
    309         else{
    310             ans+=tree.query(1,1,n,pos[ty],pos[y]);
    311             y=fa[ty];
    312             ty=top[y];
    313         }
    314     }
    315     
    316     if(pos[x]<pos[y])ans+=tree.query(1,1,n,pos[x],pos[y]);
    317     else ans+=tree.query(1,1,n,pos[y],pos[x]);
    318     
    319     return ans%mod;
    320 }
    321 
    322 inline void son_update(int root){
    323     tree.update(1,1,n,pos[root],pos[root]+size[root]-1,k);
    324 }
    325 
    326 inline ll son_query(int root){
    327     return tree.query(1,1,n,pos[root],pos[root]+size[root]-1);
    328 }
  • 相关阅读:
    string的不可变性
    <转载>网页设计中的F式布局
    Jmeter使用插件对服务器进行性能监控
    服务端的性能测试
    Linux下性能监视神器dstat用法
    服务器性能带宽实时监控
    Linux下查看系统剩余空间
    监控服务器带宽性能的命令
    监控服务器性能命令
    python3+appium app自动化实现左滑功能
  • 原文地址:https://www.cnblogs.com/running-coder-wfh/p/7617949.html
Copyright © 2011-2022 走看看