Bzoj4034:[HAOI2015]T2:树链剖分

10 篇文章 0 订阅
5 篇文章 0 订阅

题目链接:4034:[HAOI2015]T2

水树链剖分,注意开long long……

#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#define LL long long
using namespace std;
const int maxn=300010;
int n,m,tot=1,h[maxn],pos[maxn];
struct edges{int to,next;}G[maxn*2];
int size[maxn],ind=0;
LL a[maxn],b[maxn],ret=0;
int dep[maxn],fa[maxn],Belong[maxn];
struct seg{
    int l,r; LL data,sum;
    seg *lc,*rc;
    seg():data(0),sum(0){}
};
seg *root=new seg();
bool vis[maxn];

void add(int x,int y){
    G[++tot].to=y; G[tot].next=h[x]; h[x]=tot;
}

void dfs1(int x,int deep){
    dep[x]=deep; size[x]=1; vis[x]=1;
    for (int i=h[x];i;i=G[i].next){
        int v=G[i].to;
        if (vis[v]) continue;
        fa[v]=x; dfs1(v,deep+1);
        size[x]+=size[v];
    }
}

void dfs2(int x,int L){
    int k=0; Belong[x]=L;
    pos[x]=++ind; b[ind]=a[x];
    for (int i=h[x];i;i=G[i].next)
       if (dep[x]<dep[G[i].to]&&size[G[i].to]>size[k])
          k=G[i].to;
    if (!k) return; dfs2(k,L);
    for (int i=h[x];i;i=G[i].next)
       if (dep[x]<dep[G[i].to]&&k!=G[i].to)
          dfs2(G[i].to,G[i].to);
}

void push_up(seg *p){
    if (p->l+1==p->r) return; p->sum=0;
    if (p->lc) p->sum+=p->lc->sum;
    if (p->rc) p->sum+=p->rc->sum;
}

void push_down(seg *p){
    if (p->l+1==p->r) return;
    if (!p->data) return;
    if (p->lc) p->lc->sum+=(p->lc->r-p->lc->l)*p->data,
               p->lc->data+=p->data;
    if (p->rc) p->rc->sum+=(p->rc->r-p->rc->l)*p->data;
               p->rc->data+=p->data;
    p->data=0;
}

void build(seg *p,int l,int r){
    p->l=l; p->r=r;
    if (l+1==r){
        p->sum=b[l]; p->data=0;
        p->lc=p->rc=NULL; return;
    }else if (l+1<r){
        int mid=(l+r)>>1;
        p->lc=new seg();
        p->rc=new seg();
        if (l<mid) build(p->lc,l,mid);
        else p->lc=NULL;
        if (mid<r) build(p->rc,mid,r);
        else p->rc=NULL;
        push_up(p);
    }
}

void update(seg *p,int l,int r,LL v){
    push_down(p);
    if (l<=p->l&&p->r<=r){
        p->sum+=1LL*(p->r-p->l)*v;
        p->data+=v; return;
    }else{
        int mid=(p->l+p->r)>>1;
        if (l<mid) update(p->lc,l,r,v);
        if (mid<r) update(p->rc,l,r,v);
        push_up(p);
    }
}

void ask(seg *p,int l,int r){
    push_down(p);
    if (l<=p->l&&p->r<=r){
        ret+=p->sum; return;
    }else{
        int mid=(p->l+p->r)>>1;
        if (l<mid) ask(p->lc,l,r);
        if (mid<r) ask(p->rc,l,r);
    }
}

void getans(int x,int y){
    LL sum=0;
    while (Belong[x]!=Belong[y]){
        ret=0; ask(root,pos[Belong[x]],pos[x]+1);
        sum+=ret; x=fa[Belong[x]];
    } ret=0; ask(root,pos[y],pos[x]+1);
    sum+=ret; printf("%lld\n",sum);
}

int main(){
    scanf("%d%d",&n,&m);
    for (int i=1;i<=n;++i) scanf("%lld",&a[i]);
    for (int i=1;i<n;++i){
        int x,y; scanf("%d%d",&x,&y);
        add(x,y); add(y,x);
    }
    dfs1(1,1); dfs2(1,1);
    build(root,1,ind+1);
    for (int i=1;i<=m;++i){
        int opt,x; LL y;
        scanf("%d",&opt);
        if (opt==1){
            scanf("%d%lld",&x,&y);
            update(root,pos[x],pos[x]+1,y);
        }else if (opt==2){
            scanf("%d%lld",&x,&y);
            update(root,pos[x],pos[x]+size[x],y);
        }else if (opt==3){
            scanf("%d",&x);
            getans(x,1);
        }
    }
}


  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值