• 树链剖分


    定义: 

    siz[]数组,用来保存以x为根的子树节点个数

    top[]数组,用来保存当前节点的所在链的顶端节点

    hson[]数组,用来保存重儿子

    drep[]数组,用来保存当前节点的深度

    fa[]数组,用来保存当前节点的父亲

    id[]数组,用来保存树中每个节点剖分后的新编号

    两遍dfs求出以上信息,连边成重链,按照新的编号建树(有的题目这一步可省略);剩下全是线段树的操作

    查询或修改的话,因为在第二个dfs中优先构造重链,所以修改深度更深的x到top[x],x再换为fa[x],直到两点top相等;

    一般链剖100多行,我强力缩行到87行。。。。。。。。

    #include<iostream>
    #include<cstdlib>
    #include<cstring>
    #include<cstdio>
    #include<algorithm>
    #include<queue>
    #define rs ((o<<1)|1)
    #define ls (o<<1)
    #define MAXX 300010
    using namespace std;
    struct data{
      int nxt,to;
    }edge[MAXX*2];
    int segtree[MAXX*4],head[MAXX],top[MAXX],siz[MAXX],hson[MAXX],id[MAXX];
    int n,f,t,m,deep[MAXX],fa[MAXX],lazy[MAXX*4],tot,sm,a,b;
    void add(int fro,int too){edge[++tot].nxt=head[fro];edge[tot].to=too;head[fro]=tot;}
    void dfs1(int num,int father){
      hson[num]=0;deep[num]=deep[father]+1;siz[num]=1;fa[num]=father;
      for(int i=head[num];i;i=edge[i].nxt)if(father!=edge[i].to){
          int too=edge[i].to;
          dfs1(too,num);
          siz[num]+=siz[too];
          if(siz[hson[num]]<siz[too])hson[num]=too;
      }
    }
    void dfs2(int num,int toop){
      id[num]=++sm;top[num]=toop;
      if(hson[num])dfs2(hson[num],toop);
      for(int i=head[num];i;i=edge[i].nxt)if(edge[i].to!=hson[num]&&edge[i].to!=fa[num])dfs2(edge[i].to,edge[i].to);
    }
    void down(int o,int l,int r){
      int mid=(r+l)>>1;
      segtree[ls]+=(mid-l+1)*lazy[o],segtree[rs]+=lazy[o]*(r-mid);
      lazy[rs]+=lazy[o],lazy[ls]+=lazy[o],lazy[o]=0;
    }
    void update(int o,int L,int R,int ll,int rr){
      if(L!=R)down(o,L,R);
      if(L>=ll&&R<=rr){segtree[o]+=(R-L+1);lazy[o]++;return;}
      int mid=(L+R)>>1;
      if(mid<ll)update(rs,mid+1,R,ll,rr);
      else if(mid>=rr)update(ls,L,mid,ll,rr);
      else update(ls,L,mid,ll,rr),update(rs,mid+1,R,ll,rr);
      segtree[o]=segtree[ls]+segtree[rs];
    }
    int ask(int o,int L,int R,int ll,int rr){
      if(L!=R)down(o,L,R);
      if(L>=ll&&R<=rr)return segtree[o];
       int mid=(L+R)>>1;
      if(mid<ll)return ask(rs,mid+1,R,ll,rr);
      else if(mid>=rr)return ask(ls,L,mid,ll,rr);
      else return ask(ls,L,mid,ll,rr)+ask(rs,mid+1,R,ll,rr);
    }
    void work1(int x,int y){
      while(top[x]!=top[y]){
        if(deep[top[x]]<deep[top[y]])swap(x,y);
        update(1,1,n,id[top[x]],id[x]);
        x=fa[top[x]];
      }
      if(deep[x]>deep[y])swap(x,y);
      update(1,1,n,id[x],id[y]);
    }
    int work2(int x,int y){
      int ans=0;
      while(top[x]!=top[y]){
        if(deep[top[x]]<deep[top[y]])swap(x,y);
        ans+=ask(1,1,n,id[top[x]],id[x]);
        x=fa[top[x]];
      }
      if(deep[x]>deep[y])swap(x,y);
      ans+=ask(1,1,n,id[x],id[y]);
      return ans;
    }
    int main(){
      freopen("1.in","r",stdin);
      freopen("1.out","w",stdout);
      scanf("%d",&n);
      for(int i=1;i<n;++i)scanf("%d%d",&f,&t),add(f,t),add(t,f);
      dfs1(1,0),dfs2(1,1);
      scanf("%d",&m);
      for(int i=1;i<=m;++i){
        int c;
        scanf("%d%d%d",&c,&a,&b);
        if(c==1)work1(a,b);
        else printf("%d
    ",work2(a,b));
      }
      return 0;
    }
    


  • 相关阅读:
    [js高手之路] html5新增的定时器requestAnimationFrame实战进度条
    [js高手之路] html5 canvas系列教程
    [js高手之路] html5 canvas系列教程
    [js高手之路] html5 canvas系列教程
    [js高手之路] html5 canvas系列教程
    [js高手之路] html5 canvas系列教程
    [js高手之路] html5 canvas系列教程
    [js高手之路] html5 canvas系列教程
    [js高手之路] html5 canvas系列教程
    [js高手之路] html5 canvas系列教程
  • 原文地址:https://www.cnblogs.com/zzmmm/p/6501174.html
Copyright © 2020-2023  润新知