zoukankan      html  css  js  c++  java
  • Libre OJ 144、145 (DFS序)

    部分参考自博客:https://blog.csdn.net/hpu2022/article/details/81910490

    在许多问题中,由于树结构复杂通常会导致问题很棘手,因为其实非线性结构,操作起来也甚是费时。

    例如:对于一棵树,含有n个节点,每个节点拥有相应的权值,我们进行很多个操作,比如可以修改某个节点的权值,查找以某个节点为根节点的子树和。

    显然,对于这个问题,每次计算子树权值和时我们都要遍历一下各个节点,而如果我们可以用某种方式把它装化成线性结构,然后再用数组数组或者线段树去更新查询,这样不就可以更高效得多吗?

    没错,这就有了我们DFS序,它的主要思路就是将树形结构转化成线性结构,用dfs遍历一遍这棵树,进入到x节点有一个in时间戳,递归退出时有一个out 时间戳,x节点的两个时间戳之间遍历到的点,就是根为x的子树的所有节点,他们的dfs进入时间戳是递增的。同时两个时间戳构成了一个区间,x节点在这段区间的最左端,这个区间就是一棵根节点为x的子树,对于区间的操作就是其他维护方式的应用了。

    int time = 0;
    inline void dfs(int x, int fa) {
        in[x] = ++time; //进入的时间戳
        num[time] = x;  //生成新的线性结构
        for(int i = 0; i < G[x].size(); i++) {
            int cnt = G[x][i];
            if(cnt == fa) continue;
            dfs(cnt, x);
        }
        out[x] = time;  //出去的时间戳
    }

    in[x]表示映射的DFS预处理出的线性结构,也就是说x是原始节点,in[x]是x节点的新位置,num[t]表示第t个节点的编号,num[in[x]]表示的还是x。num是新序列,in表示是新序列的下标,in[x]~out[x]是x为根结点的子树,划分为一个区间。 

    Loj144 DFS序+树状数组单点更新区间查找

    题目链接:https://loj.ac/problem/144

    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<algorithm>
    #include<cmath>
    using namespace std;
    #define lson l,mid,rt<<1
    #define rson mid+1,r,rt<<1|1
    typedef long long ll;
    const ll maxn=1e6+10;
    int n,q,m,r,tot,cnt;
    ll v[maxn],in[maxn],out[maxn],head[maxn],x,num[maxn],sum[maxn];
    struct node{
        int to,next;
    }edge[2*maxn];
    void add(int u,int v){
        edge[tot].to=v;
        edge[tot].next=head[u];
        head[u]=tot++;
    }
    void dfs(int pos,int fa){
        num[++cnt]=pos;
        in[pos]=cnt;
        for(int i=head[pos];i!=-1;i=edge[i].next){
            int v=edge[i].to;
            if(v!=fa) dfs(v,pos);
        }
        out[pos]=cnt;
    }
    int lowbit(int x){
        return x&(-x);
    }
    void update(int x,int y){
        while(x<=n){
            sum[x]+=y;
            x+=lowbit(x);
        }
    }
    ll ask(int x){
        ll res=0;
        while(x){
            res+=sum[x];
            x-=lowbit(x);
        }
        return res;
    }
    int main(){
        scanf("%d%d%d",&n,&m,&r);
        for(int i=1;i<=n;i++)
            scanf("%lld",&v[i]),head[i]=-1;
        for(int i=1;i<n;i++){
            int u,v;
            scanf("%d%d",&u,&v);
            add(u,v); add(v,u);
        }
        dfs(r,-1);
        for(int i=1;i<=n;i++)
            update(in[i],v[i]);
        while(m--){
            int op,x,y;
            scanf("%d",&op);
            if(op==1){
                scanf("%d%d",&x,&y);
                update(in[x],y);
            }
            else{
                scanf("%d",&x);
                printf("%lld
    ",ask(out[x])-ask(in[x]-1));
            }
        }
        return 0;
    }

    Loj 145 DFS序+树状数组区间更新区间查找

    题目链接:https://loj.ac/problem/145

    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<algorithm>
    #include<cmath>
    using namespace std;
    #define lson l,mid,rt<<1
    #define rson mid+1,r,rt<<1|1
    typedef long long ll;
    const ll maxn=1e6+10;
    int n,q,m,r,tot,cnt;
    ll v[maxn],in[maxn],out[maxn],head[maxn],x,num[maxn],sum1[maxn],sum2[maxn];
    struct node{
        int to,next;
    }edge[2*maxn];
    void add(int u,int v){
        edge[tot].to=v;
        edge[tot].next=head[u];
        head[u]=tot++;
    }
    void dfs(int pos,int fa){
        num[++cnt]=pos;
        in[pos]=cnt;
        for(int i=head[pos];i!=-1;i=edge[i].next){
            int v=edge[i].to;
            if(v!=fa) dfs(v,pos);
        }
        out[pos]=cnt;
    }
    int lowbit(int x){return x&(-x);}
    void update(int x,ll y){
        for(int i=x;i<=n;i+=lowbit(i)){
            sum1[i]+=y;
            sum2[i]+=(x-1)*y;
        }
    }
    ll ask(int x){
        ll res=0;
        for(int i=x;i;i-=lowbit(i)){
            res+=x*sum1[i]-sum2[i];
        }
        return res;
    }
    int main(){
        scanf("%d%d%d",&n,&m,&r);
        for(int i=1;i<=n;i++)
            scanf("%lld",&v[i]),head[i]=-1;
        for(int i=1;i<n;i++){
            int u,v;
            scanf("%d%d",&u,&v);
            add(u,v); add(v,u);
        }
        dfs(r,-1);
        for(int i=1;i<=n;i++)
            update(in[i],v[i]-v[num[in[i]-1]]);
        while(m--){
            int op,x,y;
            scanf("%d",&op);
            if(op==1){
                scanf("%d%d",&x,&y);
                update(in[x],y); update(out[x]+1,-y);
            }
            else{
                scanf("%d",&x);
                printf("%lld
    ",ask(out[x])-ask(in[x]-1));
            }
        }
        return 0;
    }
  • 相关阅读:
    Anaconda和Pycharm的安装和配置
    使用XAMPP集成开发环境安装Apache、PHP的配置说明
    新兴内存技术准备突围
    使嵌入式系统调试更容易:有用的硬件和软件提示
    保护嵌入式802.11 Wi-Fi设备时需要考虑的10件事
    关键任务应用程序依赖于故障保护存储器
    模拟内存计算如何解决边缘人工智能推理的功耗挑战
    如何为嵌入式应用选择适当的SSD
    Imec推出高性能芯片的低成本冷却解决方案
    交换机应用寻找10个完美的因素
  • 原文地址:https://www.cnblogs.com/zjl192628928/p/10540148.html
Copyright © 2011-2022 走看看