zoukankan      html  css  js  c++  java
  • F--采蘑菇的克拉莉丝(重轻链的应用)

    题:https://ac.nowcoder.com/acm/contest/4010/F

    题意:给定一个树,有俩种操作,第一种节点v增加x个蘑菇;第二种根节点变为v。问每次操作完后,树上所有蘑菇走到根节点的代价。(每个蘑菇的代价为蘑菇与根节点连边最近的一条)。

    分析:对于每个操作后的根节点,我们可以把答案分为3部分,第一部分为重链的贡献,第二部分为轻链的贡献,第三部分为根节点父亲以上蘑菇的贡献。

       对于第一部分,我们需要将重链上的蘑菇数加到线段树上,方便单点查询,具体的,节点v增加x,就要节点v依据重链跳,然后将重链上的节点加上x;

       对于第二部分,在第一部分重链跳的过程中,会有轻链的转换,我们就在这时把轻链的部分加到父亲去。

       对于第三部分,只要所有蘑菇减去根节点的重轻链孩子的数目  乘上  根节点到父亲的边权即可

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    #define pb push_back
    #define lson root<<1,l,midd
    #define rson root<<1|1,midd+1,r
    const int inf=0x3f3f3f3f;
    const ll INF=1e18;
    const int M=1e6+5;
    const int mod=998244353;
    struct node{
        int v,w;
    };
    vector<node>g[M];
    int n,tot,sz[M],fa[M],id[M],son[M],top[M];
    ll sum,edgew[M],tr[M<<2],lz[M<<2],lightnum[M],ans1[M],cnt[M];
    void dfs1(int u,int f){
        sz[u]=1,fa[u]=f;
        for(auto now:g[u]){
            if(now.v!=f){
                dfs1(now.v,u);
                edgew[now.v]=now.w;
                sz[u]+=sz[now.v];
                if(sz[now.v]>sz[son[u]])
                    son[u]=now.v;
            }
        }
    }
    void dfs2(int u,int tp){
        id[u]=++tot,top[u]=tp;
        if(son[u])
            dfs2(son[u],tp);
        for(auto now:g[u]){
            if(now.v!=fa[u]&&now.v!=son[u])
                dfs2(now.v,now.v);
        }
    }
    void up(int root){
        tr[root]=tr[root<<1]+tr[root<<1|1];
    }
    void pushdown(int root){
        if(lz[root]){
            tr[root<<1]+=lz[root];
            tr[root<<1|1]+=lz[root];
            lz[root<<1]+=lz[root];
            lz[root<<1|1]+=lz[root];
            lz[root]=0;
        }
    }
    void update(int L,int R,ll x,int root,int l,int r){
        if(L<=l&&r<=R){
            tr[root]+=x;
            lz[root]+=x;
            return ;
        }
        pushdown(root);
        int midd=(l+r)>>1;
        if(L<=midd)
            update(L,R,x,lson);
        if(R>midd)
            update(L,R,x,rson);
        up(root);
    }
    ll query(int pos,int root,int l,int r){
        if(l==r){
            return tr[root];
        }
        int midd=(l+r)>>1;
        pushdown(root);
        if(pos<=midd)
            return query(pos,lson);
        else
            return query(pos,rson);
    }
    void solve(int u,ll x){
        while(u){
            update(id[top[u]],id[u],x,1,1,n);
            u=top[u];
            ans1[fa[u]]+=1ll*edgew[u]*x;
            lightnum[fa[u]]+=x;
            u=fa[u];
        }
    }
    int main(){
        scanf("%d",&n);
        for(int u,v,w,i=1;i<n;i++){
            scanf("%d%d%d",&u,&v,&w);
            g[u].pb(node{v,w});
            g[v].pb(node{u,w});
        }
        dfs1(1,0);
        dfs2(1,1);
        int m,rt=1;
        scanf("%d",&m);
        while(m--){
            int op;
            scanf("%d",&op);
            if(op==1){
                int v;
                ll x;
                scanf("%d%lld",&v,&x);
                cnt[v]+=x;
                sum+=x;
                solve(v,x);
            }
            else
                scanf("%d",&rt);
            ll ans=0;
            ll heavynum=0;
            if(id[son[rt]])
                heavynum=query(id[son[rt]],1,1,n);
            ///加上重孩子部分
            ans+=heavynum*edgew[son[rt]];
            ///加上其他孩子部分
            ans+=ans1[rt];
            ///加上父亲以上的部分
            ll othernum=sum-heavynum-lightnum[rt]-cnt[rt];
            ans+=othernum*edgew[rt];
            printf("%lld
    ",ans);
        }
        return 0;
    }
    View Code
  • 相关阅读:
    Luogu2751 [USACO Training4.2]工序安排Job Processing
    BZOJ4653: [Noi2016]区间
    BZOJ1537: [POI2005]Aut- The Bus
    CF1041F Ray in the tube
    POJ1186 方程的解数
    Luogu2578 [ZJOI2005]九数码游戏
    BZOJ2216: [Poi2011]Lightning Conductor
    CF865D Buy Low Sell High
    BZOJ1577: [Usaco2009 Feb]庙会捷运Fair Shuttle
    几类区间覆盖
  • 原文地址:https://www.cnblogs.com/starve/p/13129237.html
Copyright © 2011-2022 走看看