[HAOI2015]树上操作(树链剖分)

原题

BZOJ
洛谷

Solution

直接很简单的树链剖分然后搞一个线段树维护一下就好了?

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<math.h>
#include<algorithm>
#include<iostream>
#include<queue>
#define ll long long
#define file(a) freopen(a".in","r",stdin);freopen(a".out","w",stdout)
using namespace std;
inline int gi(){
    int sum=0,f=1;char ch=getchar();
    while(ch>'9' || ch<'0'){if(ch=='-')f=-f;ch=getchar();}
    while(ch>='0' && ch<='9'){sum=(sum<<3)+(sum<<1)+ch-'0';ch=getchar();}
    return f*sum;
}
inline ll gl(){
    ll sum=0,f=1;char ch=getchar();
    while(ch>'9' || ch<'0'){if(ch=='-')f=-f;ch=getchar();}
    while(ch>='0' && ch<='9'){sum=(sum<<3)+(sum<<1)+ch-'0';ch=getchar();}
    return f*sum;
}
const int maxn=500010;
ll old[maxn];int to[maxn<<1],nxt[maxn<<1],front[maxn],cnt;ll w[maxn];
int siz[maxn],fa[maxn],dep[maxn],son[maxn],top[maxn],b[maxn],n;
struct node{
    int l,r;ll add,val;
}tree[maxn<<4];
void Add(int u,int v){
    to[++cnt]=v;nxt[cnt]=front[u];front[u]=cnt;
}
void dfs1(int u,int f){
    siz[u]=1;fa[u]=f;dep[u]=dep[f]+1;
    for(int i=front[u];i;i=nxt[i]){
        int v=to[i];
        if(v!=fa[u]){
            dfs1(v,u);
            siz[u]+=siz[v];
            if(siz[v]>siz[son[u]])son[u]=v;
        }
    }
}
void dfs2(int u,int tp){
    top[u]=tp;b[u]=++cnt;w[cnt]=old[u];
    if(!son[u])return;
    dfs2(son[u],tp);
    for(int i=front[u];i;i=nxt[i]){
        int v=to[i];
        if(v!=son[u] && v!=fa[u])dfs2(v,v);
    }
}
void pushup(int o){
    tree[o].val=tree[o<<1].val+tree[o<<1|1].val;
}

void build(int o,int l,int r){
    tree[o].l=l;tree[o].r=r;tree[o].add=0;
    if(l==r){
        tree[o].val=w[l];
        return;
    }
    int mid=(l+r)>>1;
    build(o<<1,l,mid);build(o<<1|1,mid+1,r);
    pushup(o);
}
void pushdown(int o){
    if(tree[o].add){
        tree[o<<1].add+=tree[o].add;
        tree[o<<1|1].add+=tree[o].add;
        tree[o<<1].val+=tree[o].add*(tree[o<<1].r-tree[o<<1].l+1);
        tree[o<<1|1].val+=tree[o].add*(tree[o<<1|1].r-tree[o<<1|1].l+1);
        tree[o].add=0;
    }
}
void update(int o,int l,int r,int posl,int posr,ll k){
    if(posl<=l && r<=posr){
        tree[o].val+=k*(r-l+1);tree[o].add+=k;
        return;
    }
    pushdown(o);
    int mid=(l+r)>>1;
    if(mid>=posr)update(o<<1,l,mid,posl,posr,k);
    else if(mid<posl)update(o<<1|1,mid+1,r,posl,posr,k);
    else{
        update(o<<1,l,mid,posl,mid,k);
        update(o<<1|1,mid+1,r,mid+1,posr,k);
    }
    pushup(o);
}
ll query(int o,int l,int r,int posl,int posr){
    if(posl<=l && r<=posr)return tree[o].val;
    pushdown(o);
    int mid=(l+r)>>1;
    if(mid>=posr)return query(o<<1,l,mid,posl,posr);
    else if(mid<posl)return query(o<<1|1,mid+1,r,posl,posr);
    return query(o<<1,l,mid,posl,mid)+query(o<<1|1,mid+1,r,mid+1,posr);
}
ll Query(int u,int v){
    ll ans=0;
    while(top[u]!=top[v]){
        if(dep[top[u]]<dep[top[v]])swap(u,v);
        ans+=query(1,1,n,b[top[u]],b[u]);u=fa[top[u]];
    }
    if(dep[u]>dep[v])swap(u,v);
    return ans+query(1,1,n,b[u],b[v]);
}
int main(){
    int i,j,m,k;
    n=gi();m=gi();
    for(i=1;i<=n;i++)old[i]=gi();
    for(i=1;i<n;i++){
        int u=gi(),v=gi();
        Add(u,v);Add(v,u);
    }
    cnt=0;
    dfs1(1,1);dfs2(1,1);
    build(1,1,n);
    while(m--){
        int x,a,opt;cin>>opt>>x;
        if(opt==1){
            cin>>a;
            update(1,1,n,b[x],b[x],a);
        }
        else if(opt==2){
            cin>>a;
            update(1,1,n,b[x],b[x]+siz[x]-1,a);
        }
        else printf("%lld\n",Query(1,x));
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/cjgjh/p/9833302.html