zoukankan      html  css  js  c++  java
  • 【BZOJ-2836】魔法树 树链剖分

    2836: 魔法树

    Time Limit: 10 Sec  Memory Limit: 128 MB
    Submit: 323  Solved: 129
    [Submit][Status][Discuss]

    Description

    Input

    Output

    Sample Input

    4
    0 1
    1 2
    2 3
    4
    Add 1 3 1
    Query 0
    Query 1
    Query 2

    Sample Output

    3
    3
    2

    HINT

    Source

    Solution

    树链修改,子树查询,可以直接树链剖分搞定

    注意sum和tag要开longlong

    Code

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cmath>
    #include<cstring>
    using namespace std;
    int read()
    {
        int x=0,f=1; char ch=getchar();
        while (ch<'0' || ch>'9') {if (ch=='-') f=-1; ch=getchar();}
        while (ch>='0' && ch<='9') {x=x*10+ch-'0'; ch=getchar();}
        return x*f;
    }
    #define INF 0x7fffffff
    #define MAXN 100010
    #define MAXM 100010
    #define LL long long
    int N,Q;
    struct EdgeNode{int next,to;}edge[MAXN<<1];
    int cnt=1,head[MAXN];
    inline void AddEdge(int u,int v) {cnt++; edge[cnt].next=head[u]; head[u]=cnt; edge[cnt].to=v;}
    inline void InsertEdge(int u,int v) {AddEdge(u,v); AddEdge(v,u);}
    namespace SegmentTree
    {
        struct SegmentTreeNode{int l,r,size; LL sum,tag;}tree[MAXN<<2];
        #define ls now<<1
        #define rs now<<1|1
        inline void Update(int now) {tree[now].sum=tree[ls].sum+tree[rs].sum;}
        inline void PushDown(int now)
        {
            if (!tree[now].tag || tree[now].l==tree[now].r) return;
            tree[ls].sum+=(LL)tree[ls].size*tree[now].tag; tree[ls].tag+=tree[now].tag;
            tree[rs].sum+=(LL)tree[rs].size*tree[now].tag; tree[rs].tag+=tree[now].tag;
            tree[now].tag=0;
        }
        inline void BuildTree(int now,int l,int r)
        {
            tree[now].l=l; tree[now].r=r; tree[now].size=r-l+1;
            if (l==r) return;
            int mid=(l+r)>>1;
            BuildTree(ls,l,mid); BuildTree(rs,mid+1,r);
            Update(now);
        }
        inline void Change(int now,int L,int R,int D) 
        {
            int l=tree[now].l,r=tree[now].r;
            if (L<=l && R>=r) {tree[now].tag+=D; tree[now].sum+=(LL)tree[now].size*D; return;}
            PushDown(now);
            int mid=(l+r)>>1;
            if (L<=mid) Change(ls,L,R,D);
            if (R>mid) Change(rs,L,R,D);
            Update(now);
        }
        inline LL Query(int now,int L,int R)
        {
            int l=tree[now].l,r=tree[now].r;
            if (L<=l && R>=r) return tree[now].sum;
            PushDown(now);
            int mid=(l+r)>>1; LL re=0;
            if (L<=mid) re+=Query(ls,L,R);
            if (R>mid) re+=Query(rs,L,R);
            return re;
        }
    }
    namespace TreePartition
    {
        int fa[MAXN],size[MAXN],son[MAXN],deep[MAXN],pl[MAXN],dfn,pr[MAXN],pre[MAXN],top[MAXN];
        inline void DFS_1(int now)
        {
            size[now]=1;
            for (int i=head[now]; i; i=edge[i].next)
                if (edge[i].to!=fa[now])
                    {
                        deep[edge[i].to]=deep[now]+1;
                        fa[edge[i].to]=now;
                        DFS_1(edge[i].to);
                        size[now]+=size[edge[i].to];
                        if (size[son[now]]<size[edge[i].to]) son[now]=edge[i].to;
                    }
        }
        inline void DFS_2(int now,int chain)
        {
            top[now]=chain; pl[now]=++dfn; pre[dfn]=now;
            if (son[now]) DFS_2(son[now],chain);
            for (int i=head[now]; i; i=edge[i].next)
                if (edge[i].to!=fa[now] && edge[i].to!=son[now])
                    DFS_2(edge[i].to,edge[i].to);
            pr[now]=dfn;
        }
        inline void Change(int x,int y,int D)
        {
            while (top[x]!=top[y])
                {
                    if (deep[top[x]]<deep[top[y]]) swap(x,y);
                    SegmentTree::Change(1,pl[top[x]],pl[x],D);
                    x=fa[top[x]];
                }
            if (deep[x]>deep[y]) swap(x,y);
            SegmentTree::Change(1,pl[x],pl[y],D);
        }
        inline void Query(int x) {printf("%lld
    ",SegmentTree::Query(1,pl[x],pr[x]));}
    }
    int main()
    {
        N=read();
        for (int x,y,i=1; i<=N-1; i++) x=read()+1,y=read()+1,InsertEdge(x,y);
        TreePartition::DFS_1(1); TreePartition::DFS_2(1,1); 
        SegmentTree::BuildTree(1,1,N);
        Q=read();
        while (Q--)
            {
                char opt[10]; scanf("%s",opt); int u,v,D;
                switch (opt[0])
                    {
                        case 'A': u=read()+1,v=read()+1,D=read(); TreePartition::Change(u,v,D); break;
                        case 'Q': u=read()+1; TreePartition::Query(u); break;
                    }
            }
        return 0;
    }

    又无故RE了一次

  • 相关阅读:
    centos7系统中忘记了root管理员账号密码的解决方式
    【python之路48】生成器表达式、推导式
    小米集团信息化中台战略
    分时函数
    函数节流
    JS浮点计算问题
    要转型做前端开发了
    优秀的开发人员和测试人员应有的态度
    C#数组的笔记
    LINQ不包含列表
  • 原文地址:https://www.cnblogs.com/DaD3zZ-Beyonder/p/5890635.html
Copyright © 2011-2022 走看看