【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了一次

原文地址:https://www.cnblogs.com/DaD3zZ-Beyonder/p/5890635.html