bzoj4034

树链剖分裸题

ps:pushdown的时候区间长度(r-l+1)打成(r-r+1)居然过了样例+手造数据,害我自闭了好久qwq

/**************************************************************

    Problem: 4034

    User: syh0313

    Language: C++

    Result: Accepted

    Time:2500 ms

    Memory:21628 kb

****************************************************************/

 

#include <iostream>

#include <cstdio>

#include <cstdlib>

#include <cmath>

#include <algorithm>

#include <cstring>

#include <string>

#define lch a[n].lc

#define rch a[n].rc

using namespace std;

const int maxe=200010;

const int maxd=100010;

int n,m,topt,nt[maxe],st[maxe],to[maxe];

long long v[maxd];

int fa[maxd],size[maxd],rem[maxd];

int dfn[maxd],dfn_num,line[maxd],top[maxd];

struct tree

{

    int l,r,lc,rc;

    long long sum,tag;

}a[maxe<<1];

int cnt,root;

bool f[maxd];

void add(int x,int y)

{to[++topt]=y; nt[topt]=st[x]; st[x]=topt;}

void dfs1(int x)

{

    int p=st[x],ma=0; f[x]=1; size[x]=1;

    while (p)

    {

        if (!f[to[p]])

        {

            dfs1(to[p]);

            fa[to[p]]=x;

            size[x]+=size[to[p]];

            if (size[to[p]]>ma) {ma=size[to[p]]; rem[x]=to[p];}

        }

        p=nt[p];

    }

}

void dfs2(int x)

{

    f[x]=1; if (rem[fa[x]]==x) top[x]=top[fa[x]];else top[x]=x;

    dfn[++dfn_num]=x; line[x]=dfn_num;

    if (rem[x]) dfs2(rem[x]);

    int p=st[x];

    while (p)

    {

        if (!f[to[p]]) dfs2(to[p]);

        p=nt[p];

    }

}

void updata(int n)

{a[n].sum=a[lch].sum+a[rch].sum;}

void build_tree(int &n,int l,int r)

{

    n=++cnt; a[n].l=l; a[n].r=r;

    if (l==r) {a[n].sum=v[dfn[l]]; return;}

    int mid=(l+r)>>1;

    build_tree(lch,l,mid);

    build_tree(rch,mid+1,r);

    updata(n);

}

void pushdown(int n)

{

    if (a[n].tag)

    {

        if (lch)

        {

            a[lch].tag+=a[n].tag;

            a[lch].sum+=1ll*(a[lch].r-a[lch].l+1)*a[n].tag;

        }

        if (rch)

        {

            a[rch].tag+=a[n].tag;

            a[rch].sum+=1ll*(a[rch].r-a[rch].l+1)*a[n].tag;

        }

        updata(n);

        a[n].tag=0;

    }

}

void change(int n,int l,int r,int lc,int k)

{

    if (l==r && l==lc) {a[n].sum+=k; return;}

    if (l==r) return;

    pushdown(n);

    int mid=(l+r)>>1;

    if (lc<=mid) change(lch,l,mid,lc,k);

    else change(rch,mid+1,r,lc,k);

    updata(n);

}

void add_tree(int n,int L,int R,int l,int r,int k)

{

    if (L==l && R==r)

    {

        a[n].sum+=1ll*(r-l+1)*k;

        a[n].tag+=k;

        return;

    }

    pushdown(n);

    int mid=(L+R)>>1;

    if (r<=mid) add_tree(lch,L,mid,l,r,k);

    else if (l>=mid+1) add_tree(rch,mid+1,R,l,r,k);

    else

    {

        add_tree(lch,L,mid,l,mid,k);

        add_tree(rch,mid+1,R,mid+1,r,k);

    }

    updata(n);

}

long long qurysum(int n,int L,int R,int l,int r)

{

    //printf("%d %d %d %d %d\n",n,L,R,l,r);

    if (L==l && R==r) return a[n].sum;

    pushdown(n);

    int mid=(L+R)>>1;

    if (r<=mid) return qurysum(lch,L,mid,l,r);

    else if (l>=mid+1) return qurysum(rch,mid+1,R,l,r);

    else return qurysum(lch,L,mid,l,mid)+qurysum(rch,mid+1,R,mid+1,r);

}

long long qsum(int x)

{

    long long ans=0;

    while (top[x]!=1)

    {

        ans+=qurysum(root,1,n,line[top[x]],line[x]);

        x=fa[top[x]];

    }

    ans+=qurysum(root,1,n,1,line[x]);

return ans;

}

int main()

{

    scanf("%d%d",&n,&m);

    for (int i=1;i<=n;i++) scanf("%lld",&v[i]);

    for (int i=1;i<n;i++)

    {

        int xx,yy; scanf("%d%d",&xx,&yy);

        add(xx,yy); add(yy,xx);

    }

    dfs1(1); memset(f,0,sizeof f); dfs2(1);

    build_tree(root,1,n);

    //for (int i=1;i<=n;i++) printf("%d ",line[i]);

    //puts("");

    while (m--)

    {

        int ff,xx,yy; scanf("%d",&ff);

        if (ff==1)

        {

            scanf("%d%d",&xx,&yy);

            //printf("lalal %d\n",line[xx]);

            change(root,1,n,line[xx],yy);

        }

        else if (ff==2)

        {

            scanf("%d%d",&xx,&yy);

            //printf("laalala %d %d\n",line[xx],line[xx]+size[xx]-1);

            add_tree(root,1,n,line[xx],line[xx]+size[xx]-1,yy);

        }

        else if (ff==3)

        {

            scanf("%d",&xx);

            printf("%lld\n",qsum(xx));

            //puts("");

        }

    }

return 0;

}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值