• 【BZOJ4034】树上操作(HAOI2015)-树链剖分


    测试地址:树上操作
    做法:其实是很明显的树链剖分了,单点修改+子树修改+路径询问,写这个是为了复健,因为感觉好久没写这种代码量大的题了,结果交上去一发直接过,美滋滋。
    以下是本人代码:

    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    #define ll long long
    using namespace std;
    int n,m;
    int tot=0,first[100010]={0},in[100010]={0},out[100010]={0},tim=0;
    int dep[100010],siz[100010],son[100010],fa[100010],pos[100010],top[100010];
    ll sum[400010],tag[400010],val[100010];
    struct edge {int v,next;} e[200010];
    
    void insert(int a,int b)
    {
        e[++tot].v=b;
        e[tot].next=first[a];
        first[a]=tot;
    }
    
    void dfs1(int v)
    {
        siz[v]=1;son[v]=0;
        for(int i=first[v];i;i=e[i].next)
            if (e[i].v!=fa[v])
            {
                fa[e[i].v]=v;
                dep[e[i].v]=dep[v]+1;
                dfs1(e[i].v);
                if (siz[son[v]]<siz[e[i].v]) son[v]=e[i].v;
                siz[v]+=siz[e[i].v];
            }
    }
    
    void dfs2(int v,int p)
    {
        top[v]=p;
        pos[++tim]=v;
        in[v]=tim;
        if (son[v]) dfs2(son[v],p);
        for(int i=first[v];i;i=e[i].next)
            if (e[i].v!=fa[v]&&e[i].v!=son[v])
                dfs2(e[i].v,e[i].v);
        out[v]=tim;
    }
    
    void pushdown(int no,int l,int r)
    {
        if (tag[no]!=0)
        {
            int mid=(l+r)>>1;
            tag[no<<1]+=tag[no];
            tag[no<<1|1]+=tag[no];
            sum[no<<1]+=((ll)(mid-l+1))*tag[no];
            sum[no<<1|1]+=((ll)(r-mid))*tag[no];
            tag[no]=0;
        }
    }
    
    void pushup(int no)
    {
        sum[no]=sum[no<<1]+sum[no<<1|1];
    }
    
    void buildtree(int no,int l,int r)
    {
        if (l==r)
        {
            sum[no]=val[pos[l]];
            return;
        }
        int mid=(l+r)>>1;
        buildtree(no<<1,l,mid);
        buildtree(no<<1|1,mid+1,r);
        pushup(no);
    }
    
    void add(int no,int l,int r,int s,int t,ll val)
    {
        if (l>=s&&r<=t)
        {
            tag[no]+=val;
            sum[no]+=((ll)(r-l+1))*val;
            return;
        }
        int mid=(l+r)>>1;
        pushdown(no,l,r);
        if (s<=mid) add(no<<1,l,mid,s,t,val);
        if (t>mid) add(no<<1|1,mid+1,r,s,t,val);
        pushup(no);
    }
    
    ll segquery(int no,int l,int r,int s,int t)
    {
        if (l>=s&&r<=t)
        {
            return sum[no];
        }
        int mid=(l+r)>>1;
        ll ss=0;
        pushdown(no,l,r);
        if (s<=mid) ss+=segquery(no<<1,l,mid,s,t);
        if (t>mid) ss+=segquery(no<<1|1,mid+1,r,s,t);
        pushup(no);
        return ss;
    }
    
    ll query(int x,int y)
    {
        ll ans=0;
        while(top[x]!=top[y])
        {
            if (dep[top[x]]<dep[top[y]]) swap(x,y);
            ans+=segquery(1,1,n,in[top[x]],in[x]);
            x=fa[top[x]];
        }
        if (dep[x]<dep[y]) swap(x,y);
        ans+=segquery(1,1,n,in[y],in[x]);
        return ans;
    }
    
    int main()
    {
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++)
            scanf("%lld",&val[i]);
        for(int i=1;i<n;i++)
        {
            int a,b;
            scanf("%d%d",&a,&b);
            insert(a,b);insert(b,a);
        }
    
        fa[1]=siz[0]=0;
        dep[1]=1;
        dfs1(1);
        dfs2(1,1);
        buildtree(1,1,n);
    
        for(int i=1;i<=m;i++)
        {
            int op,a;
            ll d;
            scanf("%d",&op);
            if (op==1)
            {
                scanf("%d%lld",&a,&d);
                add(1,1,n,in[a],in[a],d);
            }
            if (op==2)
            {
                scanf("%d%lld",&a,&d);
                add(1,1,n,in[a],out[a],d);
            }
            if (op==3)
            {
                scanf("%d",&a);
                printf("%lld
    ",query(1,a));
            }
        }
    
        return 0;
    }
    
  • 相关阅读:
    iOS:UIResponser控件的介绍(响应者)
    iOS:触摸控件UITouch、事件类UIEvent
    iOS:触摸事件和手势识别的介绍
    iOS:菜单控制器和菜单项:UIMenuController和UIMenuItem
    iOS:对GCD中 同步、异步、并行、串行的见解
    iOS:转载:同步、异步、并行、串行的详解
    iOS:GCD技术——仅仅执行一次和执行多次 dispatch_once和dispatch_apply
    pes and ts stream, how to convert
    5分钟搞定内存字节对齐
    sed 使用
  • 原文地址:https://www.cnblogs.com/Maxwei-wzj/p/9793613.html
Copyright © 2020-2023  润新知