zoukankan      html  css  js  c++  java
  • 【bzoj4372】 烁烁的游戏【动态树分治】

    烁烁的游戏

    Description

    背景:烁烁很喜欢爬树,这吓坏了树上的皮皮鼠。
    题意:
    给定一颗n个节点的树,边权均为1,初始树上没有皮皮鼠。
    烁烁他每次会跳到一个节点u,把周围与他距离不超过d的节点各吸引出w只皮皮鼠。皮皮鼠会被烁烁吸引,所以会一直待在节点上不动。
    烁烁很好奇,在当前时刻,节点u有多少个他的好朋友—皮皮鼠。
    大意:
    给一颗n个节点的树,边权均为1,初始点权均为0,m次操作:
    Q x:询问x的点权。
    M x d w:将树上与节点x距离不超过d的节点的点权均加上w。

    Input

    第一行两个正整数:n,m
    接下来的n-1行,每行三个正整数u,v,代表u,v之间有一条边。
    接下来的m行,每行给出上述两种操作中的一种。

    Output

    对于每个Q操作,输出当前x节点的皮皮鼠数量。

    解法:

    先考虑暴力。对于每一次查询,把整棵树遍历一遍,对于每个遍历到的节点,加上当前节点到查询点的距离的所有的修改值。最后得到的就是这个点的点权。
    有了思路,就上树分治啦!每个点开2棵可区间修改的李超线段树。
    第一棵线段树:以子树中的每一个点到自己的距离为下标,维护每一种距离的修改值。
    第二棵线段树:以子树中的每一个点到自己的父亲的距离为下标,维护每一种距离的修改值。
    修改:设要修改的点为u,要与u距离不超过d1的所有点加上w。在向上爬的过程中,设当前爬到节点为i,u到fa[i]的距离为d2。则将fa[i]的第一棵线段树下标为0~d1-d2都加上w,再将用于去掉重复的i的第二棵线段树下标为0~d1-d2都加上w。
    查询:其实统计答案的原理和暴力是一样的。在向上爬的过程中,设当前点的父亲到查询点的距离为d。对于每个祖先节点,答案加上这个点的父亲的第一棵线段树下标为d的修改值,再减去这个点的第二棵线段树下标为d的修改值,目的仍然是减去重复的。这大概就是动态树分治的一种套路吧。
    于是搞定了。
    代码:

    #include<cstdio>
    #include<algorithm>
    using namespace std;
    const int N=100005;
    int n,m,u,v,d,cnt,head[N],to[N*2],nxt[N*2];
    int idx,lg2[N*2],dfn[N],dep[N],siz[N],pos[N*2],f[N*2][20];
    int mi,size,rt,fa[N];
    int tot,root[N][2],tag[20000005],ch[20000005][2];
    bool vis[N];
    char s[5];
    void adde(int u,int v){
        to[++cnt]=v;
        nxt[cnt]=head[u];
        head[u]=cnt;
    }
    void dfs(int pre,int u){
        dfn[u]=++idx;
        pos[idx]=u;
        int v;
        for(int i=head[u];i;i=nxt[i]){
            v=to[i];
            if(v!=pre){
                dep[v]=dep[u]+1;
                dfs(u,v);
                pos[++idx]=u;
            }
        }
    }
    void st(){
        for(int i=1;i<=idx;i++){
            f[i][0]=pos[i];
        }
        for(int j=1;j<=20;j++){
            for(int i=1;i+(1<<j)-1<=idx;i++){
                if(dep[f[i][j-1]]<dep[f[i+(1<<(j-1))][j-1]]){
                    f[i][j]=f[i][j-1];
                }else{
                    f[i][j]=f[i+(1<<(j-1))][j-1];
                }
            }
        }
    }
    int lca(int u,int v){
        if(dfn[u]>dfn[v]){
            swap(u,v);
        }
        int k=lg2[dfn[v]-dfn[u]];
        if(dep[f[dfn[u]][k]]<dep[f[dfn[v]-(1<<k)+1][k]]){
            return f[dfn[u]][k];
        }else{
            return f[dfn[v]-(1<<k)+1][k];
        }
    }
    void dfsroot(int pre,int u){
        siz[u]=1;
        int v,mx=0;
        for(int i=head[u];i;i=nxt[i]){
            v=to[i];
            if(v!=pre&&!vis[v]){
                dfsroot(u,v);
                siz[u]+=siz[v];
                mx=max(mx,siz[v]);
            }
        }
        mx=max(mx,size-siz[u]);
        if(mx<mi){
            mi=mx;
            rt=u;
        }
    }
    int dis(int u,int v){
        return dep[u]+dep[v]-2*dep[lca(u,v)];
    }
    void build(int pre,int u){
        vis[u]=true;
        fa[u]=pre;
        int v;
        for(int i=head[u];i;i=nxt[i]){
            v=to[i];
            if(!vis[v]){
                mi=size=siz[v];
                dfsroot(u,v);
                build(u,rt);
            }
        }
    }
    void upd(int &o,int l,int r,int L,int R,int v){
        if(!o){
            o=++tot;
        }
        if(L==l&&R==r){
            tag[o]+=v;
            return;
        }
        int mid=(l+r)/2;
        if(R<=mid){
            upd(ch[o][0],l,mid,L,R,v);
        }else if(L>mid){
            upd(ch[o][1],mid+1,r,L,R,v);
        }else{
            upd(ch[o][0],l,mid,L,mid,v);
            upd(ch[o][1],mid+1,r,mid+1,R,v);
        }
    }
    int qry(int o,int l,int r,int k){
        if(!o){
            return 0;
        }
        if(l==r){
            return tag[o];
        }
        int mid=(l+r)/2;
        if(k<=mid){
            return tag[o]+qry(ch[o][0],l,mid,k);
        }{
            return tag[o]+qry(ch[o][1],mid+1,r,k);
        }
    }
    int query(int u){
        int ret=qry(root[u][0],0,n,0),tmp;
        for(int i=u;fa[i];i=fa[i]){
            tmp=dis(fa[i],u);
            ret+=qry(root[fa[i]][0],0,n,tmp)-qry(root[i][1],0,n,tmp);
        }
        return ret;
    }
    void update(int u,int d,int w){
        upd(root[u][0],0,n,0,d,w);
        int tmp;
        for(int i=u;fa[i];i=fa[i]){
            tmp=dis(fa[i],u);
            if(tmp>d){
                continue;
            }
            upd(root[fa[i]][0],0,n,0,d-tmp,w);
            upd(root[i][1],0,n,0,d-tmp,w);
        }
    }
    int main(){
        for(int i=2;i<=200000;i++){
            lg2[i]=lg2[i/2]+1;
        }
        scanf("%d%d",&n,&m);
        for(int i=1;i<n;i++){
            scanf("%d%d",&u,&v);
            adde(u,v);
            adde(v,u);
        }
        dfs(0,1);
        st();
        mi=size=n;
        dfsroot(0,1);
        build(0,rt);
        for(int i=1;i<=m;i++){
            scanf("%s%d",s,&u);
            if(s[0]=='Q'){
                printf("%d
    ",query(u));              
            }else{
                scanf("%d%d",&d,&v);
                update(u,d,v);                                             
            }
        }
        return 0;
    }
  • 相关阅读:
    【xsy2479】counting 生成函数+多项式快速幂
    【 2019北京集训测试赛(十)】 子矩阵 二分
    【2019北京集训测试赛(七)】 操作 分治+FFT+生成函数
    Python 导出项目依赖/导出所有安装模块/打包数据
    数据结构与算法 介绍以及常见的算法排序
    爬虫 scrapy框架
    爬虫 开发者工具详解
    爬虫 selenium+Xpath 爬取动态js页面元素内容
    爬虫 解析库re,Beautifulsoup,
    爬虫 requests模块的其他用法 抽屉网线程池回调爬取+保存实例,gihub登陆实例
  • 原文地址:https://www.cnblogs.com/2016gdgzoi471/p/9476905.html
Copyright © 2011-2022 走看看