zoukankan      html  css  js  c++  java
  • P3899|线段树dfs序上子树合并

    自己调试不出来了
    转载一份代码留作模板

    主要是想学一下线段树在dfs序上处理子树的问题,谁知道这么难写,不如新学的主席树好做啊

    #include<bits/stdc++.h>
    using namespace std;
    const int mv=3e5,ml=19;
    
    /*
    dfs序上:线段树合并子树 
    动态开点思想 
    */
    
    int n,q;
    struct node{
        int ls,rs;
        long long num;//每个点的siz-1之和。
    }tree[2*mv*ml+3];
    int tot=0;
    
    inline void up(int x) {
        tree[x].num=tree[tree[x].ls].num+tree[tree[x].rs].num;
    }
    
    void update(int x,int tl,int tr,int w,int ad) {
        if(tl==tr) {
            tree[x].num+=ad;
            return;
        }
        int mid=(tl+tr)/2;
        if(w<=mid) {
            if(!tree[x].ls) tree[x].ls=++tot;
            update(tree[x].ls,tl,mid,w,ad);
        }
        if(w>mid) {
            if(!tree[x].rs) tree[x].rs=++tot;
            update(tree[x].rs,mid+1,tr,w,ad);
        }
        up(x);
    }
    
    long long query(int x,int tl,int tr,int l,int r) {
        if(!x) return 0;
        if(tl==l&&r==tr) return tree[x].num;
        int mid=(tl+tr)/2;long long ans=0;
        //没建出来的地方值肯定为0,不用递归。
        if(l<=mid&&tree[x].ls) 
            ans+=query(tree[x].ls,tl,mid,l,min(mid,r));
        if(r>mid&&tree[x].rs) 
            ans+=query(tree[x].rs,mid+1,tr,max(l,mid+1),r);
        return ans;
    }
    
    int merge(int x,int y,int tl,int tr) {
        if(x==0||y==0) return x|y;//有空的则返回非空的。
        if(tl==tr) {
            int now=++tot;
            tree[now].num=tree[x].num+tree[y].num;
            return now;
        }
        int mid=(tl+tr)/2,now=++tot;//为了不改变儿子线段树的值,必须新建节点。
        tree[now].ls=merge(tree[x].ls,tree[y].ls,tl,mid);
        tree[now].rs=merge(tree[x].rs,tree[y].rs,mid+1,tr);
        up(now);
        return now;
    }
    
    vector<int>g[mv+3];
    int fa[mv+3],h[mv+3],siz[mv+3],dfn[mv+3];
    //父亲、深度、子树大小、该点对应线段树树根的编号。
    void dfs(int u) {
        siz[u]=1;
        for(int j=0;j<(int)g[u].size();j++) {
            int v=g[u][j];
            if(fa[u]==v) continue;
            fa[v]=u;
            h[v]=h[u]+1;
            dfs(v);
            siz[u]+=siz[v];
        }
        dfn[u]=++tot; //dfs序时间戳 
        update(dfn[u],1,n,h[u],siz[u]-1);//在线段树深度为h处加答案。
        for(int j=0;j<(int)g[u].size();j++) {
            int v=g[u][j];
            if(fa[u]==v) continue;
            dfn[u]=merge(dfn[u],dfn[v],1,n);//合并 子树 
        }
    }
    
    int main() {
        cin>>n>>q;
        int u,v;
        for(int e=1;e<n;e++) {
            scanf("%d%d",&u,&v);
            g[u].push_back(v);
            g[v].push_back(u);
        }
        h[1]=1;//深度从1开始记。
        dfs(1);
        int K;
        for(int z=1;z<=q;z++) {
            scanf("%d%d",&u,&K);
            long long ans=1ll*min(h[u]-1,K)*(siz[u]-1);//上方谈笑风生。
            ans+=query(dfn[u],1,n,h[u]+1,h[u]+K);//下方谈笑风生。
            printf("%lld
    ",ans);
        }
        return 0;
    }
    
  • 相关阅读:
    monkeyrunner之夜神模拟器的安装与使用(二)
    monkeyrunner之安卓开发环境搭建(一)
    MySQL 返回未包含在group by中的列
    MySQL数据库初体验
    MongoDB安装
    关于数据库你必须知道的事~
    PostgreSQL中的MVCC 事务隔离
    深入浅出MySQL之索引为什么要下推?
    Java集合篇:Map集合的几种遍历方式及性能测试
    Oracle11g:数据库恢复总结
  • 原文地址:https://www.cnblogs.com/fisherss/p/12231110.html
Copyright © 2011-2022 走看看