• 博客园logo
  • 会员
  • 周边
  • 新闻
  • 博问
  • 闪存
  • 众包
  • 赞助商
  • Chat2DB
    • 搜索
      所有博客
    • 搜索
      当前博客
  • 写随笔 我的博客 短消息 简洁模式
    用户头像
    我的博客 我的园子 账号设置 会员中心 简洁模式 ... 退出登录
    注册 登录

yongchaoD

  • 博客园
  • 联系
  • 订阅
  • 管理

公告

View Post

DFS 序 1(小树剖)

题目来源:https://vjudge.net/contest/642764#problem/H
//
题意:给你一棵树,树上的每一个节点都有自己的权值,现在有两种操作:op1:在某一个节点的权值增加x。op2:求a节点子树所有的权值之和。
//
算法介绍:
树剖:将树剖解为一连串的链式结构,并对所有节点重新编号,链式结构中的节点新编号都是连续的,一个节点子树的所有编号也都是连续的。 能对树上某两个节点的dfs路径上的权值增改,查询(涉及到跳点)。某个节点子树节点的权值增改,查询。把树转为链,通过线段树区间维护。
//
思路:这个题仅仅是对子树操作(阉割了跳点操作),在dfs中,仅仅只需要把树节点重新编为连续号,用dfn[i]记录i节点的新编号,用over[i]记录i节点子树的最后节点的新编号。
一棵树dfs序新编号好后就是:

//
可以看到,树剖后,所有的子树编号都是按照dfs序的连续编号,绿色圈中,例如对8节点的子树操作,子树结尾编号就是over[8]=12。然后讲新编号放入线段树里维护就行了。
//
题解:

点击查看代码
#include<bits/stdc++.h>
#define int long long
#define lp p<<1
#define rp p<<1|1
using namespace std;
const int N=1e6+9;
int n,q,R,op,tot=0,a,x;

struct Nod{
    int sum,add;
}tree[N<<2];

vector<int>arr(N),dfn(N),over(N),num(N);
vector<int>G[N];
//dfn:新编号,
//over:i节点dfs序的末节点
//num:新旧节点映射

void dfs(int u,int fa){//小数剖:对树节点重新编号
   dfn[u]=++tot,num[tot]=u;
   for(auto v:G[u]){
       if(v==fa) { continue;}
       dfs(v,u);
   }
   over[u]=tot;
}

void pushup(int p){
    tree[p].sum=tree[lp].sum+tree[rp].sum;
}

void pushdown(int p,int len){
    if(tree[p].add){
        tree[lp].sum+=(len-(len>>1))*tree[p].add,tree[rp].sum+=(len>>1)*tree[p].add;
        tree[lp].add+=tree[p].add,tree[rp].add+=tree[p].add;
        tree[p].add=0;
    }
}

void build(int s,int t,int p){
    if(s==t){
        tree[p].sum=arr[num[s]];//权值还是原来编号记录的,要映射回去
        return;
    }
    int m=(s+t)>>1;
    build(s,m,lp),build(m+1,t,rp);
    pushup(p);
}

void update(int l,int r,int k,int s,int t,int p){
    if(l<=s && r>=t){
        tree[p].sum+=(t-s+1)*k;
        tree[p].add+=k;
        return;
    }
    pushdown(p,t-s+1);
    int m=(s+t)>>1;
    if(l<=m) { update(l,r,k,s,m,lp);}
    if(r>=m+1) {update(l,r,k,m+1,t,rp);}
    pushup(p);
}

int query(int l,int r,int s,int t,int p){
    if(l<=s && r>=t){
        return tree[p].sum;
    }
    pushdown(p,t-s+1);
    int m=(s+t)>>1,sum=0;
    if(l<=m) {sum=query(l,r,s,m,lp);}
    if(r>=m+1) {sum+=query(l,r,m+1,t,rp);}
    pushup(p);
    return sum;
}

signed main()
{
    cin>>n>>q>>R;
    for(int i=1;i<=n;i++){cin>>arr[i];}

    int u,v;
    for(int i=1;i<n;i++){
        cin>>u>>v;
        G[u].push_back(v);
        G[v].push_back(u);
    }
     dfs(R,R);
     build(1,n,1);

     while(q--){
         cin>>op;
         if(op==1){//a节点权值+x
             cin>>a>>x;
           update(dfn[a],dfn[a],x,1,n,1);
         }
         else if(op==2){//查询a的子树所有权值和
           cin>>a;
           cout<<query(dfn[a],over[a],1,n,1)<<'\n';
         }
     }
    return 0;
}

posted on 2024-07-26 10:34  yongchaoD  阅读(17)  评论(0)    收藏  举报

刷新页面返回顶部
 
博客园  ©  2004-2026
浙公网安备 33010602011771号 浙ICP备2021040463号-3