树的DFS序

树的 DFS

简意:将树上问题转化为线性问题。

例题:

- MEG-Megalopolis

有一棵节点数为 n 的树,给定 m+n1 组询问,每组询问有两种操作。

  1. A x y,将 x 节点和 y 节点间的边权改为 0,每条边会被修改恰好一次。(每次只修改一条边)

  2. W x,求 1 号点到 x 号点路径上的边权和。

初始所有边权值都为 1

我们可以先 dfs 一遍找出这棵树的 dfs 序,其长度为 2n :

void dfs(int pos,int fa){
    l[pos] = idx;
    idx++;
    for(int to : tree[pos]){
        if(to != fa){
            dfs(to,pos);
        }
    }
    r[pos] = idx;idx++;
}

其中 l 数组为记录某一节点在 dfs 序中第一次出现的位置,而 r 数组为记录某一节点在 dfs 序中第二次出现的位置。

而每个节点会且仅会出现两次。

我们对于节点 2n ,建一颗线段树或树状数组,将 l[x] 位置上的值加1,将 r[x] 的值减1,查询 1x 路径上的边权和时就查询 1l[x] 的前缀和就行了.

code

#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
const int MAXN = 250005;
int n,m;
vector<int> tree[MAXN];
int l[MAXN],r[MAXN];
int idx = 1;

struct TREE{
    int l,r;
    int val;
}seg[MAXN << 4];
void build(int pos,int l,int r){
    seg[pos].l = l;
    seg[pos].r = r;
    if(l == r){
        return;
    }
    int mid = (l + r) / 2;
    int ls = pos * 2;
    int rs = pos * 2 + 1;
    build(ls,l,mid);
    build(rs,mid + 1,r);
}
void fix(int pos,int x,int val){
    int l = seg[pos].l;
    int r = seg[pos].r;
    if(l == r && l == x){
        seg[pos].val += val;
        return;
    }
    int mid = (l + r) / 2;
    int ls = pos * 2;
    int rs = pos * 2 + 1;
    if(mid >= x) fix(ls,x,val);
    if(mid < x) fix(rs,x,val);
    seg[pos].val = seg[ls].val + seg[rs].val; 
}
int query(int pos,int nl,int nr){
    int l = seg[pos].l;
    int r = seg[pos].r;
    if(l >= nl && r <= nr){
        return seg[pos].val;
    }
    int ans = 0;
    int mid = (l + r) / 2;
    int ls = pos * 2;
    int rs = pos * 2 + 1;
    if(mid >= nl) ans += query(ls,nl,nr);
    if(mid < nr) ans += query(rs,nl,nr);
    return ans;
}
void dfs(int pos,int fa){
    l[pos] = idx;
    idx++;
    for(int to : tree[pos]){
        if(to != fa){
            dfs(to,pos);
        }
    }
    r[pos] = idx;idx++;
}
int main(){
    scanf("%d", &n);
    build(1,1,3 * n);
    for(int i = 1;i < n;i++){
        int x,y;
        scanf("%d%d", &x, &y);
        tree[x].push_back(y);
        tree[y].push_back(x);
    }
    dfs(1,0);
    for(int i = 2;i <= n;i++){
    	fix(1,l[i],1);
    	fix(1,r[i],-1);
	}
    scanf("%d", &m);
    for(int i = 1;i <= m + n - 1;i++){
        char op;
        cin>>op;
        int x,y;
        if(op == 'A'){
            scanf("%d%d", &x, &y);
            if(l[x] < l[y]){
                swap(x,y);
            }
            fix(1,l[x],-1);
            fix(1,r[x],1);
        }else{
            scanf("%d", &x);
            printf("%d\n",query(1,1,l[x]));
        }
    }
    return 0;
}
posted @   wyl123ly  阅读(8)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
点击右上角即可分享
微信分享提示