学习笔记--树链剖分

  • 前言

    树链剖分是一个很好用的处理树上统计信息的方法,大致思想就是把树上路径分成\(log N\)条链,再用线段树之类的数据结构维护一下,所以时间复杂度得到了保障

  • 怎么做

    个人认为这篇讲的很好:

    https://www.cnblogs.com/George1994/p/7821357.html

  • 注意几点

    debug树链剖分对于我来说真是个痛苦的过程,查了近一个小时错才查出来.

    首先你要只要线段树上序列是什么?他们是\(dfs\_2\)中的每个树节点的\(dfs\)顺序存在\(dfn[]\)中,\(rnk[]\)则记录对应\(dfn[]\)对应的节点编号

    build函数

    void build(int now,int l,int r){
    if(l==r){
        mx[now]=sum[now]=w[rnk[l]];//注意是rnk[l]
        return ;
    }
    int mid=(l+r)>>1;
    build(now<<1,l,mid);
    build(now<<1|1,mid+1,r);
    sum[now]=sum[now<<1]+sum[now<<1|1];
    mx[now]=max(mx[now<<1],mx[now<<1|1]);
    return ;
    }
    

    dfs之前的操作

    dep[1]=1,fa[1]=1;//假设root是1
    dfs_1(1);
    dfs_2(1,1);
    build(1,1,n);
    

    未完待续

  • 例题1;

    https://www.luogu.org/problemnew/show/P2590

    代码:

    扫描二维码关注公众号,回复: 1874801 查看本文章
    #include <iostream>
    #include <cstdio>
    #include <cstdlib>
    #include <algorithm>
    #include <cstring>
    #include <cctype>
    #include <map>
    #define ri register int 
    #define ll long long 
    using namespace std;
    const int maxn=30305;
    const int inf=0x7fffffff;
    template <class T>inline void read(T &x){
      x=0;int ne=0;char c;
      while(!isdigit(c=getchar()))ne=c=='-';
      x=c-48;
      while(isdigit(c=getchar()))x=(x<<3)+(x<<1)+c-48;
      x=ne?-x:x;
      return ;
    }
    int n,q,t,w[maxn],dta;
    int dep[maxn],size[maxn],top[maxn],son[maxn],dfn[maxn],rnk[maxn],fa[maxn],cnt=0;
    struct Edge{
      int ne,to;
    }edge[maxn<<1];
    int h[maxn],num_edge=0;
    inline void add_edge(int f,int to){
      edge[++num_edge].ne=h[f];
      edge[num_edge].to=to;
      h[f]=num_edge;
    }
    int sum[maxn<<2],mx[maxn<<2],L,R;
    /*inline void pushdown(int now,int ln,int rn){
      if(tag[now]){
          sum[now<<1]+=tag[now]*ln;
          sum[now<<1|1]+=tag[now]*rn;
          tag[now<<1]+=tag[now];
          tag[now<<1|1]+=tag[now];
          tag[now]=0;
      }
      return ;
    }*/
    void build(int now,int l,int r){
      if(l==r){
          mx[now]=sum[now]=w[rnk[l]];
          return ;
      }
      int mid=(l+r)>>1;
      build(now<<1,l,mid);
      build(now<<1|1,mid+1,r);
      sum[now]=sum[now<<1]+sum[now<<1|1];
      mx[now]=max(mx[now<<1],mx[now<<1|1]);
      return ;
    }
    void update(int now,int l,int r){
      if(l==r){
          sum[now]=mx[now]=dta;
          return ;
      }
      int mid=(l+r)>>1;
      if(t<=mid)update(now<<1,l,mid);
      else update(now<<1|1,mid+1,r);
      sum[now]=sum[now<<1]+sum[now<<1|1];
      mx[now]=max(mx[now<<1],mx[now<<1|1]);
      return ;
    }
    int query_mx(int now,int l,int r){
      if(L<=l&&r<=R){
          return mx[now];
      }
      int mid=(l+r)>>1,ans=-inf;
      if(L<=mid)ans=max(ans,query_mx(now<<1,l,mid));
      if(mid<R)ans=max(ans,query_mx(now<<1|1,mid+1,r));
      return ans;
    }
    int  query_sum(int now,int l,int r){
      if(L<=l&&r<=R){
          return sum[now];
      }
      int mid=(l+r)>>1,ans=0;
      if(L<=mid)ans+=query_sum(now<<1,l,mid);
      if(mid<R)ans+=query_sum(now<<1|1,mid+1,r);
      return ans;
    }
    void dfs_1(int now){
      int v;size[now]=1;
      //cout<<now<<"-----"<<endl;
      for(ri i=h[now];i;i=edge[i].ne){
          v=edge[i].to;
          if(v==fa[now])continue;
          fa[v]=now,dep[v]=dep[now]+1;
          dfs_1(v);
          size[now]+=size[v];
          if(!son[now]||size[son[now]]<size[v])son[now]=v;
      }
      return ;
    }
    void dfs_2(int now,int t){
      int v;top[now]=t;
      dfn[now]=++cnt,rnk[cnt]=now;
      //cout<<now<<' '<<dfn[now]<<' '<<cnt<<endl;
      if(!son[now])return ;
      dfs_2(son[now],t);
      for(ri i=h[now];i;i=edge[i].ne){
          v=edge[i].to;
          if(v==fa[now]||v==son[now])continue;
          dfs_2(v,v);
      }
      return ;
    }
    void query_path_sum(int x,int y){
      int ans=0;
      while(top[x]!=top[y]){
          if(dep[top[x]]<dep[top[y]])swap(x,y);
          L=dfn[top[x]],R=dfn[x];
          ans+=query_sum(1,1,n);
          x=fa[top[x]];
      }
      if(dfn[x]>dfn[y])swap(x,y);
      L=dfn[x],R=dfn[y];
      ans+=query_sum(1,1,n);
      printf("%d\n",ans);
      return ;
    }
    void query_path_mx(int x,int y){
      int ans=-inf;
      //cout<<x<<' '<<y<<endl;
      while(top[x]!=top[y]){
          if(dep[top[x]]<dep[top[y]])swap(x,y);
          L=dfn[top[x]],R=dfn[x];
          ans=max(ans,query_mx(1,1,n));
          x=fa[top[x]];
      }
      //cout<<x<<' '<<y<<endl;
      if(dfn[x]>dfn[y])swap(x,y);
      L=dfn[x],R=dfn[y];
      //cout<<'-'<<L<<' '<<R<<endl;
      ans=max(ans,query_mx(1,1,n));
      //cout<<x<<' '<<y<<endl;
      printf("%d\n",ans);
      return ;
    }
    void update_set(int x){
      t=dfn[x];
      update(1,1,n);
      return ;
    }
    int main(){
      int x,y;
      char opt[64];
      read(n);
      for(ri i=1;i<n;i++){
          read(x),read(y);
          //cout<<x<<' '<<y<<endl;
          add_edge(x,y);
          add_edge(y,x);
      }
      for(ri i=1;i<=n;i++){
          read(w[i]);
          dep[i]=fa[i]=son[i]=0;
      }
      dep[1]=1,fa[1]=1;
      dfs_1(1);
      dfs_2(1,1);
      build(1,1,n);
      read(q);
      while(q--){
          scanf("%s",opt);
          if(opt[0]=='C'){
              read(x),read(y);
              dta=y;
              update_set(x);
          }
          else if(opt[1]=='M'){
              read(x),read(y);
              //cout<<x<<' '<<y<<'*'<<endl;
              query_path_mx(x,y);
          }
          else {
              read(x),read(y);
              query_path_sum(x,y);
          }
      }   
      return 0;
    }
  • 例题2:(待填坑)

    https://www.luogu.org/problemnew/show/P3384

    我比较傻逼现在还不知道为什么只得了30分

猜你喜欢

转载自www.cnblogs.com/Rye-Catcher/p/9265860.html
今日推荐