1 条题解

  • 0
    @ 2025-10-8 17:09:14

    C14【模板】点分树 动态点分治

    #include <algorithm>
    #include <cstdio>
    #include <cstring>
    using namespace std;
    const int N=100010;
    
    int n,m,w[N];
    int idx,h[N],to[N*2],ne[N*2];
    void add(int x,int y){
      to[++idx]=y;ne[idx]=h[x];h[x]=idx;
    }
    
    struct LCA{ //最近公共祖先
      int dep[N],fa[N][20];
      void dfs(int u, int f){
        dep[u]=dep[f]+1;
        fa[u][0]=f;
        for(int i=1; i<=19; i++) 
          fa[u][i]=fa[fa[u][i-1]][i-1]; 
        for(int i=h[u]; i; i=ne[i])
          if(to[i]!=f) dfs(to[i], u);        
      }
      int lca(int u, int v){
        if(dep[u]<dep[v])swap(u, v);
        for(int i=19; ~i; i--)
          if(dep[fa[u][i]]>=dep[v])u=fa[u][i];
        if(u==v) return v;
        for(int i=19; ~i; i--)
          if(fa[u][i]!=fa[v][i])
            u=fa[u][i], v=fa[v][i];
        return fa[u][0];
      }
      int getdis(int x,int y){ //计算两点在原树中的距离
        return dep[x]+dep[y]-2*dep[lca(x,y)];
      }
    } lca;
    
    struct SegTree{ //线段树
      int cnt,root[N],sum[N*40],lc[N*40],rc[N*40];
      void change(int &u,int l,int r,int d,int v){
        if(!u) u=++cnt;
        if(l==r){sum[u]+=v; return;}
        int mid=l+r>>1;
        if(d<=mid) change(lc[u],l,mid,d,v);
        else change(rc[u],mid+1,r,d,v);
        sum[u]=sum[lc[u]]+sum[rc[u]];
      }
      int query(int u,int l,int r,int x,int y){
        if(!u || r<x || l>y) return 0;
        if(x<=l&&r<=y) return sum[u];
        int mid=l+r>>1;
        return query(lc[u],l,mid,x,y)
              +query(rc[u],mid+1,r,x,y);
      }
    } sg,ch;
    
    struct PointTree{ //点分树
      int root,sum,siz[N],mxp[N],del[N];
      void findwc(int x,int fa){ //找重心
        siz[x]=1;
        mxp[x]=0;
        for(int i=h[x]; i; i=ne[i])
          if(to[i] != fa && !del[to[i]]){
            findwc(to[i],x);
            siz[x] += siz[to[i]];
            mxp[x]=max(mxp[x],siz[to[i]]);
          }
        mxp[x]=max(mxp[x],sum-siz[x]);
        if(mxp[x]<mxp[root]) root=x;
      }
      void getroot(int x,int size){ //找出根
        mxp[root=0]=sum=size;
        findwc(x,-1);
        findwc(root,-1);//确保siz[]正确  
      }
    
      int dis[N][20],dep[N],fa[N];
      void build_sg(int x,int fa,int wc,int d){
        sg.change(sg.root[wc],0,n,d,w[x]);
        for(int i=h[x]; i; i=ne[i])
          if(to[i] != fa && !del[to[i]]) 
            build_sg(to[i],x,wc,d+1);
      }
      void build_ch(int x,int fa,int wc,int d){
        ch.change(ch.root[wc],0,n,d,w[x]);
        for(int i=h[x]; i; i=ne[i])
          if(to[i] != fa && !del[to[i]]) 
            build_ch(to[i],x,wc,d+1);
      }
      void build(int x){ //建点分树
        del[x]=1;
        build_sg(x,-1,x,0);
        for(int i=h[x]; i; i=ne[i]){
          if(del[to[i]])continue;
          getroot(to[i],siz[to[i]]);    
          build_ch(to[i],-1,root,1);
          fa[root]=x; dep[root]=dep[x]+1;
          build(root);
        }
      }
      
      void init(){
        getroot(1,n); //找根
        build(root);  //建树
        lca.dfs(1,-1); //求lca
        for(int i=1; i<=n; i++) //原树中的点距
          for(int j=i; j; j=fa[j]) 
            dis[i][dep[i]-dep[j]]=lca.getdis(i,j);  
      } 
      int query(int x,int y){
        int res=sg.query(sg.root[x],0,n,0,y);
        for(int i=x; fa[i]; i=fa[i]){
          int d=dis[x][dep[x]-dep[fa[i]]];
          res+=sg.query(sg.root[fa[i]],0,n,0,y-d);
          res-=ch.query(ch.root[i],0,n,0,y-d);
        }
        return res;
      }
      void change(int x,int y){
        sg.change(sg.root[x],0,n,0,y-w[x]);
        for(int i=x; fa[i]; i=fa[i]){
          int d=dis[x][dep[x]-dep[fa[i]]];
          sg.change(sg.root[fa[i]],0,n,d,y-w[x]);
          ch.change(ch.root[i],0,n,d,y-w[x]);
        } 
      }
    } pt;
    
    int main(){
      int u,v,op,x,y,last=0;
      scanf("%d%d",&n,&m);
      for(int i=1; i <= n; i++) scanf("%d",&w[i]);
      for(int i=1; i < n; i++)
        scanf("%d%d",&u,&v),add(u,v),add(v,u);
        
      pt.init(); 
      while(m--){
        scanf("%d%d%d",&op,&x,&y);
        x^=last; y^=last;
        if(op == 0){
          last=pt.query(x,y);
          printf("%d\n",last);
        }
        else pt.change(x,y), w[x]=y;
      }
      return 0;
    }
    
    • 1

    信息

    ID
    5395
    时间
    2000ms
    内存
    1024MiB
    难度
    9
    标签
    递交数
    12
    已通过
    3
    上传者