【BZOJ4034】【HAOI2015】树上操作

题目请自行查阅传送门

典型的树剖题,线段树维护操作,记一下子树在线段树内范围即可。

时间复杂度:\( O(m \log^{2} n) \)

#include <stdio.h>
#define MN 100005
#define Mn (1<<17)
#define ls (k<<1)
#define rs (k<<1|1)
#define mid (l+r>>1)
#define ll long long
ll sum[Mn<<1],mark[Mn<<1];
int val[MN],siz[MN],dep[MN],fa[MN],top[MN],son[MN],head[MN],l[MN],r[MN],n,q,cnt,dfsn,root=1;
struct tree{int to,nxt;}edge[MN<<1];
inline int in(){
    int x=0,f=1;
    char ch=getchar();
    while (ch<'0'||ch>'9') f=ch=='-'?-1:1,ch=getchar();
    while (ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
    return x*f;
}
inline void ins(int x,int y){edge[++cnt].to=y,edge[cnt].nxt=head[x],head[x]=cnt;}
inline void dfs1(int u,int f,int d){
    siz[u]=1,dep[u]=d,fa[u]=f;
    for (register int i=head[u]; i; i=edge[i].nxt)
        if (edge[i].to!=f){
            dfs1(edge[i].to,u,d+1);siz[u]+=siz[edge[i].to];
            if (siz[edge[i].to]>siz[son[u]]) son[u]=edge[i].to;
        }
}
inline void dfs2(int u,int tp){
    top[u]=tp,l[u]=(++dfsn);if (son[u]) dfs2(son[u],tp);
    for (register int i=head[u]; i; i=edge[i].nxt)
        if (edge[i].to!=son[u]&&edge[i].to!=fa[u]) dfs2(edge[i].to,edge[i].to); r[u]=dfsn;
}
inline void pushdown(int k,int l,int r){
    if (l==r||!mark[k]) return;register int x=r-l+1;
    mark[ls]+=mark[k],mark[rs]+=mark[k];
    sum[ls]+=(x-(x>>1))*mark[k];sum[rs]+=(x>>1)*mark[k];mark[k]=0;
}
inline void combine(int k){sum[k]=sum[ls]+sum[rs];}
inline void A(int l,int r,int a,int b,int k,int ad){
    if (a<=l&&r<=b){mark[k]+=ad;sum[k]+=1ll*ad*(r-l+1);return;}
    pushdown(k,l,r);if (a<=mid) A(l,mid,a,b,ls,ad);
    if (b>mid) A(mid+1,r,a,b,rs,ad);combine(k);
}
inline ll Q(int l,int r,int a,int b,int k){
    if (l==a&&r==b) return sum[k];pushdown(k,l,r);
    if (b<=mid) return Q(l,mid,a,b,ls);
    if (a>mid) return Q(mid+1,r,a,b,rs);
    return Q(l,mid,a,mid,ls)+Q(mid+1,r,mid+1,b,rs);
}
inline ll query(int x){
    register ll res=0;
    while (top[x]!=root) res+=Q(1,n,l[top[x]],l[x],1),x=fa[top[x]];
    return res+=Q(1,n,l[root],l[x],1); 
}
void init(){
    n=in(),q=in();for (int i=1; i<=n; ++i) val[i]=in();
    for (register int i=1; i<n; ++i){
        register int x=in(),y=in();
        ins(x,y); ins(y,x);
    }
    dfs1(root,1,1);dfs2(root,root);
    for (register int i=1; i<=n; ++i) A(1,n,l[i],l[i],1,val[i]);
}
void solve(){
    while(q--){
        register int op=in(),x=in(),ad;
        if (op^3){
            ad=in();if (op&1) A(1,n,l[x],l[x],1,ad);
            else A(1,n,l[x],r[x],1,ad);
         }else printf("%lld\n",query(x));
    }
}
int main(){init(); solve(); return 0;}

 

posted @ 2017-04-26 09:23  Melacau  阅读(138)  评论(0编辑  收藏  举报