zoukankan      html  css  js  c++  java
  • SHOI 2012 魔法树

    洛谷 P3833 [SHOI2012]魔法树

    洛谷传送门

    题目背景

    SHOI2012 D2T3

    题目描述

    Harry Potter 新学了一种魔法:可以让改变树上的果子个数。满心欢喜的他找到了一个巨大的果树,来试验他的新法术。

    这棵果树共有N个节点,其中节点0是根节点,每个节点u的父亲记为fa[u],保证有fa[u] < u。初始时,这棵果树上的果子都被 Dumbledore 用魔法清除掉了,所以这个果树的每个节点上都没有果子(即0个果子)。

    不幸的是,Harry 的法术学得不到位,只能对树上一段路径的节点上的果子个数统一增加一定的数量。也就是说,Harry 的魔法可以这样描述:

    Add u v d

    表示将点u和v之间的路径上的所有节点的果子个数都加上d。

    接下来,为了方便检验 Harry 的魔法是否成功,你需要告诉他在释放魔法的过程中的一些有关果树的信息:

    Query u

    表示当前果树中,以点u为根的子树中,总共有多少个果子?

    输入格式

    第一行一个正整数N (1 ≤ N ≤ 100000),表示果树的节点总数,节点以0,1,…,N − 1标号,0一定代表根节点。

    接下来N − 1行,每行两个整数a,b (0 ≤ a < b < N),表示a是b的父亲。

    接下来是一个正整数Q(1 ≤ ? ≤ 100000),表示共有Q次操作。

    后面跟着Q行,每行是以下两种中的一种:

    1. A u v d,表示将u到v的路径上的所有节点的果子数加上d;0 ≤ u,v <N,0 < d < 100000
    2. Q u,表示询问以u为根的子树中的总果子数,注意是包括u本身的。

    输出格式

    对于所有的Query操作,依次输出询问的答案,每行一个。答案可能会超过2^32 ,但不会超过10^15 。

    输入输出样例

    输入 #1复制

    输出 #1复制

    题解:

    一道树链剖分的裸题。

    当然,倍增LCA的较朴素做法如果数据水一些的话是过不去的,建议大家借此机会学一下树链剖分。

    (顺便推下自己讲树链剖分的比较好的博客,博客阅读口味更佳):

    浅谈树链剖分

    本题代码在这!!

    再赋上本题的代码:

    顺便赋上自己丑陋的代码:

    #include<cstdio>
    #include<iostream>
    #include<algorithm>
    #define int long long
    #define lson pos<<1
    #define rson pos<<1|1
    using namespace std;
    const int maxn=1e5+1;
    int n,tot,cnt,q;
    int head[maxn],nxt[maxn<<1],to[maxn<<1];
    int fa[maxn],deep[maxn],size[maxn],son[maxn];
    int id[maxn],top[maxn];
    int tree[maxn<<2],lazy[maxn<<2];
    void add(int x,int y)
    {
        to[++tot]=y;
        nxt[tot]=head[x];
        head[x]=tot;
    }
    void dfs1(int x,int f)
    {
        deep[x]=deep[f]+1;
        fa[x]=f;
        size[x]=1;
        for(int i=head[x];i;i=nxt[i])
        {
            int y=to[i];
            if(y==f)
                continue;
            dfs1(y,x);
            size[x]+=size[y];
            if(!son[x]||size[son[x]]<size[y])
                son[x]=y;
        }
    }
    void dfs2(int x,int t)
    {
        id[x]=++cnt;
        top[x]=t;
        if(!son[x])
            return;
        dfs2(son[x],t);
        for(int i=head[x];i;i=nxt[i])
        {
            int y=to[i];
            if(y==fa[x]||y==son[x])
                continue;
            dfs2(y,y);
        }
    }
    void mark(int pos,int l,int r,int k)
    {
        tree[pos]+=(r-l+1)*k;
        lazy[pos]+=k;
    }
    void pushdown(int pos,int l,int r)
    {
        int mid=(l+r)>>1;
        mark(lson,l,mid,lazy[pos]);
        mark(rson,mid+1,r,lazy[pos]);
        lazy[pos]=0;
    }
    void update(int pos,int l,int r,int x,int y,int k)
    {
        int mid=(l+r)>>1;
        if(x<=l && r<=y)
        {
            mark(pos,l,r,k);
            return;
        }
        pushdown(pos,l,r);
        if(x<=mid)
            update(lson,l,mid,x,y,k);
        if(y>mid)
            update(rson,mid+1,r,x,y,k);
        tree[pos]=tree[lson]+tree[rson];
    }
    void upd_chain(int x,int y,int k)
    {
        while(top[x]!=top[y])
        {
            if(deep[top[x]]<deep[top[y]])
                swap(x,y);
            update(1,1,n,id[top[x]],id[x],k);
            x=fa[top[x]];
        }
        if(deep[x]<deep[y])
            swap(x,y);
        update(1,1,n,id[y],id[x],k);
    }
    int query(int pos,int l,int r,int x,int y)
    {
        int ret=0;
        int mid=(l+r)>>1;
        if(x<=l && r<=y)
            return tree[pos];
        pushdown(pos,l,r);
        if(x<=mid)
            ret+=query(lson,l,mid,x,y);
        if(y>mid)
            ret+=query(rson,mid+1,r,x,y);
        return ret;
    }
    int q_subtree(int x)
    {
        return query(1,1,n,id[x],id[x]+size[x]-1);
    }
    signed main()
    {
        scanf("%lld",&n);
        for(int i=1;i<n;i++)
        {
            int x,y;
            scanf("%lld%lld",&x,&y);
            x++,y++;
            add(x,y);
            add(y,x);
        }
        dfs1(1,0);
        dfs2(1,1);
        scanf("%lld",&q);
        while(q--)
        {
            char k;
            cin>>k;
            if(k=='A')
            {
                int x,y,d;
                scanf("%lld%lld%lld",&x,&y,&d);
                x++,y++;
                upd_chain(x,y,d);
            }
            else
            {
                int x;
                scanf("%lld",&x);
                x++;
                printf("%lld
    ",q_subtree(x));
            }
        }
        return 0;
    }
    
  • 相关阅读:
    GKCTF2020
    PTA的Python练习题(二十三)
    Web刷题之旅(三)
    Web刷题之旅(二)
    Web刷题之旅(一)-攻防世界 站
    PTA的Python练习题(补)
    Ctfshow
    Ctfshow
    15、实操篇——Vi和Vim编译器
    13、14、实操篇——远程登录到Linux服务器和远程上传下载文件
  • 原文地址:https://www.cnblogs.com/fusiwei/p/11607657.html
Copyright © 2011-2022 走看看