zoukankan      html  css  js  c++  java
  • 专题训练之树链剖分

    推荐几个博客:https://blog.csdn.net/y990041769/article/details/40348013 树链剖分详解

    https://blog.csdn.net/ACdreamers/article/details/10591443 树链剖分原理

    1.(HDOJ3966)http://acm.hdu.edu.cn/showproblem.php?pid=3966

    题意:给一棵树,并给定各个点权的值,然后有3种操作:

    I C1 C2 K: 把C1与C2的路径上的所有点权值加上K

    D C1 C2 K:把C1与C2的路径上的所有点权值减去K

    Q C:查询节点编号为C的权值

    分析:模板题(关于点权的树链剖分),先进行剖分,然后用树状数组去维护即可。区间修改,单点查询

      1 #include<cstdio>
      2 #include<cstring>
      3 #include<algorithm>
      4 using namespace std;
      5 const int maxn=50010;
      6 struct Edge
      7 {
      8     int to,nxt;
      9 }edge[maxn*2];
     10 int head[maxn],tot;
     11 int top[maxn]; //top[v]表示v所在重链的顶端节点
     12 int fa[maxn]; //父亲节点
     13 int dep[maxn]; //深度
     14 int num[maxn]; //num[v]表示以v为根的子树的节点数
     15 int p[maxn]; //每个节点剖分后的新编号 
     16 int fp[maxn]; //当前节点在树状数组中的位置 
     17 int son[maxn]; //重儿子
     18 int pos,n;
     19 int bit[maxn];
     20 int a[maxn];
     21 
     22 void init()
     23 {
     24     tot=0;
     25     memset(head,-1,sizeof(head));
     26     pos=1; //使用树状数组,编号从1开始
     27     memset(son,-1,sizeof(son)); 
     28 } 
     29 
     30 void addedge(int u,int v)
     31 {
     32     edge[tot].to=v;
     33     edge[tot].nxt=head[u];
     34     head[u]=tot++;
     35 }
     36 
     37 void dfs1(int u,int pre,int d)
     38 {
     39     dep[u]=d;
     40     fa[u]=pre;
     41     num[u]=1;
     42     for ( int i=head[u];i!=-1;i=edge[i].nxt )
     43     {
     44         int v=edge[i].to;
     45         if ( v!=pre )
     46         {
     47             dfs1(v,u,d+1);
     48             num[u]+=num[v];
     49             if ( son[u]==-1 || num[v]>num[son[u]] ) son[u]=v;
     50         }    
     51     }    
     52 } 
     53 
     54 void dfs2(int u,int sp)
     55 {
     56     top[u]=sp;
     57     p[u]=pos++;    
     58     fp[p[u]]=u;
     59     if ( son[u]==-1 ) return;
     60     dfs2(son[u],sp);
     61     for ( int i=head[u];i!=-1;i=edge[i].nxt )
     62     {
     63         int v=edge[i].to;
     64         if ( v!=son[u] && v!=fa[u] ) dfs2(v,v);
     65     }
     66 } 
     67 
     68 int lowbit(int x)
     69 {
     70     return x&(-x);
     71 }
     72 
     73 void add(int k,int val)
     74 {
     75     while ( k<=n )
     76     {
     77         bit[k]+=val;
     78         k+=lowbit(k);
     79     }
     80 }
     81 
     82 int sum(int k)
     83 {
     84     int s=0;
     85     while ( k )
     86     {
     87         s+=bit[k];
     88         k-=lowbit(k);
     89     }
     90     return s;
     91 }
     92 
     93 void update(int u,int v,int val) //u->v的路径上点的值的改变
     94 {
     95     int f1=top[u],f2=top[v];
     96     int tmp=0;
     97     while ( f1!=f2 )
     98     {
     99         if ( dep[f1]<dep[f2] )
    100         {
    101             swap(f1,f2);
    102             swap(u,v);
    103         }
    104         add(p[f1],val);
    105         add(p[u]+1,-val);
    106         u=fa[f1];
    107         f1=top[u];
    108     }
    109     if ( dep[u]>dep[v] ) swap(u,v);
    110     add(p[u],val);
    111     add(p[v]+1,-val);
    112 } 
    113 
    114 int main()
    115 {
    116     int m,P,u,v,C1,C2,K;
    117     char op[10];
    118     while ( scanf("%d%d%d",&n,&m,&P)!=EOF )
    119     {
    120         init();
    121         for ( int i=1;i<=n;i++ ) scanf("%d",&a[i]);
    122         while ( m-- )
    123         {
    124             scanf("%d%d",&u,&v);
    125             addedge(u,v);
    126             addedge(v,u);
    127         }
    128         dfs1(1,0,0);
    129         dfs2(1,1);
    130         memset(bit,0,sizeof(bit));
    131         for ( int i=1;i<=n;i++ )
    132         {
    133             add(p[i],a[i]);
    134             add(p[i]+1,-a[i]);
    135         }
    136         while ( P-- )
    137         {
    138             scanf("%s",op);
    139             if ( op[0]=='Q' ) 
    140             {
    141                 scanf("%d",&u);
    142                 printf("%d
    ",sum(p[u]));
    143             }
    144             else
    145             {
    146                 scanf("%d%d%d",&C1,&C2,&K);
    147                 if ( op[0]=='D' ) K=-K;
    148                 update(C1,C2,K);
    149             }
    150         }
    151     }
    152     return 0;
    153 }
    HDOJ3966(带注释)
      1 #include<cstdio>
      2 #include<cstring>
      3 #include<algorithm>
      4 using namespace std;
      5 const int maxn=50010;
      6 struct Edge
      7 {
      8     int to,nxt;
      9 }edge[maxn*2];
     10 int head[maxn],tot;
     11 int top[maxn]; 
     12 int fa[maxn]; 
     13 int dep[maxn]; 
     14 int num[maxn];
     15 int p[maxn]; 
     16 int fp[maxn]; 
     17 int son[maxn]; 
     18 int pos,n;
     19 int bit[maxn];
     20 int a[maxn];
     21 
     22 void init()
     23 {
     24     tot=0;
     25     memset(head,-1,sizeof(head));
     26     pos=1; 
     27     memset(son,-1,sizeof(son)); 
     28 } 
     29 
     30 void addedge(int u,int v)
     31 {
     32     edge[tot].to=v;
     33     edge[tot].nxt=head[u];
     34     head[u]=tot++;
     35 }
     36 
     37 void dfs1(int u,int pre,int d)
     38 {
     39     dep[u]=d;
     40     fa[u]=pre;
     41     num[u]=1;
     42     for ( int i=head[u];i!=-1;i=edge[i].nxt )
     43     {
     44         int v=edge[i].to;
     45         if ( v!=pre )
     46         {
     47             dfs1(v,u,d+1);
     48             num[u]+=num[v];
     49             if ( son[u]==-1 || num[v]>num[son[u]] ) son[u]=v;
     50         }    
     51     }    
     52 } 
     53 
     54 void dfs2(int u,int sp)
     55 {
     56     top[u]=sp;
     57     p[u]=pos++;    
     58     fp[p[u]]=u;
     59     if ( son[u]==-1 ) return;
     60     dfs2(son[u],sp);
     61     for ( int i=head[u];i!=-1;i=edge[i].nxt )
     62     {
     63         int v=edge[i].to;
     64         if ( v!=son[u] && v!=fa[u] ) dfs2(v,v);
     65     }
     66 } 
     67 
     68 int lowbit(int x)
     69 {
     70     return x&(-x);
     71 }
     72 
     73 void add(int k,int val)
     74 {
     75     while ( k<=n )
     76     {
     77         bit[k]+=val;
     78         k+=lowbit(k);
     79     }
     80 }
     81 
     82 int sum(int k)
     83 {
     84     int s=0;
     85     while ( k )
     86     {
     87         s+=bit[k];
     88         k-=lowbit(k);
     89     }
     90     return s;
     91 }
     92 
     93 void update(int u,int v,int val)
     94 {
     95     int f1=top[u],f2=top[v];
     96     int tmp=0;
     97     while ( f1!=f2 )
     98     {
     99         if ( dep[f1]<dep[f2] )
    100         {
    101             swap(f1,f2);
    102             swap(u,v);
    103         }
    104         add(p[f1],val);
    105         add(p[u]+1,-val);
    106         u=fa[f1];
    107         f1=top[u];
    108     }
    109     if ( dep[u]>dep[v] ) swap(u,v);
    110     add(p[u],val);
    111     add(p[v]+1,-val);
    112 } 
    113 
    114 int main()
    115 {
    116     int m,P,u,v,C1,C2,K;
    117     char op[10];
    118     while ( scanf("%d%d%d",&n,&m,&P)!=EOF )
    119     {
    120         init();
    121         for ( int i=1;i<=n;i++ ) scanf("%d",&a[i]);
    122         while ( m-- )
    123         {
    124             scanf("%d%d",&u,&v);
    125             addedge(u,v);
    126             addedge(v,u);
    127         }
    128         dfs1(1,0,0);
    129         dfs2(1,1);
    130         memset(bit,0,sizeof(bit));
    131         for ( int i=1;i<=n;i++ )
    132         {
    133             add(p[i],a[i]);
    134             add(p[i]+1,-a[i]);
    135         }
    136         while ( P-- )
    137         {
    138             scanf("%s",op);
    139             if ( op[0]=='Q' ) 
    140             {
    141                 scanf("%d",&u);
    142                 printf("%d
    ",sum(p[u]));
    143             }
    144             else
    145             {
    146                 scanf("%d%d%d",&C1,&C2,&K);
    147                 if ( op[0]=='D' ) K=-K;
    148                 update(C1,C2,K);
    149             }
    150         }
    151     }
    152     return 0;
    153 }
    HDOJ3966(不带注释)

    2.(POJ2763)http://poj.org/problem?id=2763

    题意:给一个数,边之间有权值,然后两种操作,第一种:求任意两点的权值和,第二,修改树上两点的权值。

    分析:模板题(关于边权的树链剖分),用线段树维护,同时用边的孩子节点来表示该边。单点查询,区间修改

      1 #include<cstdio>
      2 #include<cstring>
      3 #include<algorithm>
      4 #define lson l,m,rt*2
      5 #define rson m+1,r,rt*2+1
      6 #define root 1,n,1
      7 using namespace std;
      8 const int maxn=100010;
      9 struct Edge{
     10     int to,nxt;
     11 }edge[maxn*2];
     12 int head[maxn],tot;
     13 int top[maxn],fa[maxn],dep[maxn],num[maxn],p[maxn],fp[maxn],son[maxn];
     14 int pos,n;
     15 int sum[maxn*4];
     16 int e[maxn][3];
     17 
     18 void pushup(int rt)
     19 {
     20     sum[rt]=sum[rt*2]+sum[rt*2+1];
     21 }
     22 
     23 void build(int l,int r,int rt)
     24 {
     25     if ( l==r )
     26     {
     27         sum[rt]=0;
     28         return;
     29     }
     30     int m=(l+r)/2;
     31     build(lson);
     32     build(rson);
     33     pushup(rt);
     34 }
     35 
     36 void update(int k,int val,int l,int r,int rt)
     37 {
     38     if ( l==r ) 
     39     {
     40         sum[rt]=val;
     41         return;
     42     }
     43     int m=(l+r)/2;
     44     if ( k<=m ) update(k,val,lson);
     45     else update(k,val,rson);
     46     pushup(rt);
     47 }
     48 
     49 int query(int L,int R,int l,int r,int rt)
     50 {
     51     if ( L<=l && r<=R ) return sum[rt];
     52     int m=(l+r)/2;
     53     int ret=0;
     54     if ( L<=m ) ret+=query(L,R,lson);
     55     if ( R>m ) ret+=query(L,R,rson);
     56     return ret;
     57 }
     58 
     59 void init()
     60 {
     61     tot=0;
     62     memset(head,-1,sizeof(head));
     63     pos=0;
     64     memset(son,-1,sizeof(son));
     65 }
     66 
     67 void addedge(int u,int v)
     68 {
     69     edge[tot].to=v;
     70     edge[tot].nxt=head[u];
     71     head[u]=tot++;
     72 }
     73 
     74 void dfs1(int u,int pre,int d)
     75 {
     76     dep[u]=d;
     77     fa[u]=pre;
     78     num[u]=1;
     79     for ( int i=head[u];i!=-1;i=edge[i].nxt )
     80     {
     81         int v=edge[i].to;
     82         if ( v!=pre )
     83         {
     84             dfs1(v,u,d+1);
     85             num[u]+=num[v];
     86             if ( son[u]==-1 || num[v]>num[son[u]] ) son[u]=v;
     87         }
     88     }
     89 }
     90 
     91 void dfs2(int u,int sp)
     92 {
     93     top[u]=sp;
     94     p[u]=pos++;
     95     fp[p[u]]=u;
     96     if ( son[u]==-1 ) return;
     97     dfs2(son[u],sp);
     98     for ( int i=head[u];i!=-1;i=edge[i].nxt )
     99     {
    100         int v=edge[i].to;
    101         if ( v!=son[u] && v!=fa[u] ) dfs2(v,v);
    102     }
    103 }
    104 
    105 int find(int u,int v)
    106 {
    107     int f1=top[u],f2=top[v];
    108     int tmp=0;
    109     while ( f1!=f2 )
    110     {
    111         if ( dep[f1]<dep[f2] ) 
    112         {
    113             swap(f1,f2);
    114             swap(u,v);
    115         }
    116         tmp+=query(p[f1],p[u],root);
    117         u=fa[f1],f1=top[u];
    118     }
    119     if ( u==v ) return tmp;
    120     if ( dep[u]>dep[v] ) swap(u,v);
    121     return tmp+query(p[son[u]],p[v],root);
    122 }
    123 
    124 int main()
    125 {
    126     int q,s,u,v,op;
    127     while ( scanf("%d%d%d",&n,&q,&s)!=EOF )
    128     {
    129         init();
    130         for ( int i=1;i<n;i++ )
    131         {
    132             for ( int j=0;j<3;j++ ) scanf("%d",&e[i][j]);
    133             addedge(e[i][0],e[i][1]);
    134             addedge(e[i][1],e[i][0]);
    135         }
    136         dfs1(1,0,0);
    137         dfs2(1,1);
    138         build(root);
    139         for ( int i=1;i<n;i++ )
    140         {
    141             if ( dep[e[i][0]]>dep[e[i][1]] ) swap(e[i][0],e[i][1]);
    142             update(p[e[i][1]],e[i][2],root);
    143         }
    144         while ( q-- )
    145         {
    146             scanf("%d",&op);
    147             if ( op==0 )
    148             {
    149                 scanf("%d",&v);
    150                 printf("%d
    ",find(s,v));
    151                 s=v;
    152             }
    153             else 
    154             {
    155                 scanf("%d%d",&u,&v);
    156                 update(p[e[u][1]],v,root);
    157             }
    158         }
    159     }
    160     return 0;
    161 }
    POJ2763

    3.(POJ3237)http://poj.org/problem?id=3237

    题意:给你由N个结点组成的树。树的节点被编号为1到N,边被编号为1到N-1。每一条边有一个权值。然后你要在树上执行一系列指令。指令可以是如下三种之一:
    CHANGE i v:将第i条边的权值改成v。
    NEGATE a b:将点a到点b路径上所有边的权值变成其相反数。
    QUERY a b:找出点a到点b路径上各边的最大权值。

    分析:关于边权的树链剖分,既有单点更新又有区间更新,区间查询。对于操作2,设置变量add(lazy标记),0表示不乘-1,1表示乘-1。同时需要同时设置最大值和最小值。

      1 #include<cstdio>
      2 #include<cstring>
      3 #include<algorithm>
      4 #define lson l,m,rt*2
      5 #define rson m+1,r,rt*2+1
      6 #define root 1,n,1
      7 using namespace std;
      8 const int maxn=100010;
      9 const int inf=1e9;
     10 struct Edge{
     11     int to,nxt;
     12 }edge[maxn*2];
     13 struct node{
     14     int Max,Min,add;
     15 }arr[maxn*4];
     16 int head[maxn],tot;
     17 int top[maxn],fa[maxn],dep[maxn],num[maxn],p[maxn],fp[maxn],son[maxn];
     18 int pos,n;
     19 int e[maxn][3];
     20 
     21 void pushup(int rt)
     22 {
     23     arr[rt].Max=max(arr[rt*2].Max,arr[rt*2+1].Max);
     24     arr[rt].Min=min(arr[rt*2].Min,arr[rt*2+1].Min);
     25 }
     26 
     27 void pushdown(int rt,int m)
     28 {
     29     if ( m==0 ) return;
     30     if ( arr[rt].add )
     31     {
     32         arr[rt*2].Max*=-1;
     33         arr[rt*2].Min*=-1;
     34         arr[rt*2].add^=1;
     35         arr[rt*2+1].Max*=-1;
     36         arr[rt*2+1].Min*=-1;
     37         arr[rt*2+1].add^=1;
     38         swap(arr[rt*2].Max,arr[rt*2].Min);
     39         swap(arr[rt*2+1].Max,arr[rt*2+1].Min);
     40         arr[rt].add=0;
     41     }
     42 }
     43 
     44 void build(int l,int r,int rt)
     45 {
     46     if ( l==r )
     47     {
     48         arr[rt].Max=0;
     49         arr[rt].Min=0;
     50         arr[rt].add=0;
     51         return;
     52     }
     53     int m=(l+r)/2;
     54     build(lson);
     55     build(rson);
     56     pushup(rt);
     57 }
     58 
     59 void update(int k,int val,int l,int r,int rt)
     60 {
     61     if ( l==r ) 
     62     {
     63         arr[rt].Max=val;
     64         arr[rt].Min=val;
     65         arr[rt].add=0;
     66         return;
     67     }
     68     pushdown(rt,r-l+1);
     69     int m=(l+r)/2;
     70     if ( k<=m ) update(k,val,lson);
     71     else update(k,val,rson);
     72     pushup(rt);
     73 }
     74 
     75 void update_(int L,int R,int l,int r,int rt)
     76 {
     77     if ( L<=l && r<=R )
     78     {
     79         arr[rt].Max*=-1;
     80         arr[rt].Min*=-1;
     81         arr[rt].add^=1;
     82         swap(arr[rt].Max,arr[rt].Min);
     83         return;
     84     }
     85     pushdown(rt,r-l+1);
     86     int m=(l+r)/2;
     87     if ( L<=m ) update_(L,R,lson);
     88     if ( m<R ) update_(L,R,rson);
     89     pushup(rt);
     90 }
     91 
     92 int query(int L,int R,int l,int r,int rt)
     93 {
     94     if ( L<=l && r<=R ) return arr[rt].Max;
     95     pushdown(rt,r-l+1);
     96     int m=(l+r)/2;
     97     int ret=-inf;
     98     if ( L<=m ) ret=max(ret,query(L,R,lson));
     99     if ( R>m ) ret=max(ret,query(L,R,rson));
    100     pushup(rt);
    101     return ret;
    102 }
    103 
    104 void init()
    105 {
    106     tot=0;
    107     memset(head,-1,sizeof(head));
    108     pos=0;
    109     memset(son,-1,sizeof(son));
    110 }
    111 
    112 void addedge(int u,int v)
    113 {
    114     edge[tot].to=v;
    115     edge[tot].nxt=head[u];
    116     head[u]=tot++;
    117 }
    118 
    119 void dfs1(int u,int pre,int d)
    120 {
    121     dep[u]=d;
    122     fa[u]=pre;
    123     num[u]=1;
    124     for ( int i=head[u];i!=-1;i=edge[i].nxt )
    125     {
    126         int v=edge[i].to;
    127         if ( v!=pre )
    128         {
    129             dfs1(v,u,d+1);
    130             num[u]+=num[v];
    131             if ( son[u]==-1 || num[v]>num[son[u]] ) son[u]=v;
    132         }
    133     }
    134 }
    135 
    136 void dfs2(int u,int sp)
    137 {
    138     top[u]=sp;
    139     p[u]=pos++;
    140     fp[p[u]]=u;
    141     if ( son[u]==-1 ) return;
    142     dfs2(son[u],sp);
    143     for ( int i=head[u];i!=-1;i=edge[i].nxt )
    144     {
    145         int v=edge[i].to;
    146         if ( v!=son[u] && v!=fa[u] ) dfs2(v,v);
    147     }
    148 }
    149 
    150 int find(int u,int v)
    151 {
    152     int f1=top[u],f2=top[v];
    153     int tmp=-inf;
    154     while ( f1!=f2 )
    155     {
    156         if ( dep[f1]<dep[f2] ) 
    157         {
    158             swap(f1,f2);
    159             swap(u,v);
    160         }
    161         tmp=max(tmp,query(p[f1],p[u],root));
    162         u=fa[f1],f1=top[u];
    163     }
    164     if ( u==v ) return tmp;
    165     if ( dep[u]>dep[v] ) swap(u,v);
    166     return max(tmp,query(p[son[u]],p[v],root));
    167 }
    168 
    169 void find_(int u,int v)
    170 {
    171     int f1=top[u],f2=top[v];
    172     while ( f1!=f2 )
    173     {
    174         if ( dep[f1]<dep[f2] ) 
    175         {
    176             swap(f1,f2);
    177             swap(u,v);
    178         }
    179         update_(p[f1],p[u],root);
    180         u=fa[f1],f1=top[u];
    181     }
    182     if ( u==v ) return;
    183     if ( dep[u]>dep[v] ) swap(u,v);
    184     update_(p[son[u]],p[v],root);
    185     return;
    186 }
    187 
    188 int main()
    189 {
    190     int q,s,u,v,T;
    191     char op[10];
    192     scanf("%d",&T);
    193     while ( T-- )
    194     {
    195         scanf("%d",&n);
    196         init();
    197         for ( int i=1;i<n;i++ )
    198         {
    199             for ( int j=0;j<3;j++ ) scanf("%d",&e[i][j]);
    200             addedge(e[i][0],e[i][1]);
    201             addedge(e[i][1],e[i][0]);
    202         }
    203         dfs1(1,0,0);
    204         dfs2(1,1);
    205         build(root);
    206         for ( int i=1;i<n;i++ )
    207         {
    208             if ( dep[e[i][0]]>dep[e[i][1]] ) swap(e[i][0],e[i][1]);
    209             update(p[e[i][1]],e[i][2],root);
    210         }
    211         while ( scanf("%s",op)==1 )
    212         {
    213             if ( op[0]=='D' ) break;
    214             scanf("%d%d",&u,&v); 
    215             if ( op[0]=='Q' ) printf("%d
    ",find(u,v));
    216             else if ( op[0]=='C' ) update(p[e[u][1]],v,root);
    217             else find_(u,v);
    218         } 
    219     }
    220     return 0;
    221 }
    POJ3237
  • 相关阅读:
    Hbase flusher源码解析(flush全代码流程解析)
    HBase行锁原理及实现
    Hbase源码之 compact源码(二)
    hbase源码之 compact源码(一)
    手动下载jar包导入mvn repo的方法
    JAVA Api 调用Hbase报错锦集
    Hbase Filter之PrefixFilter
    Hbase Filter之FilterList
    windows环境中hbase源码编译遇到的问题
    Hbase put写入源码分析
  • 原文地址:https://www.cnblogs.com/HDUjackyan/p/9279777.html
Copyright © 2011-2022 走看看