萌新求助树链剖分,T了五个点QAQ
查看原帖
萌新求助树链剖分,T了五个点QAQ
238408
vectorwyxSD省选加油楼主2020/10/12 22:06

RT,谢谢巨佬们QAQ

#include<iostream>
#include<cstdio>
#define ls(p) p<<1
#define rs(p) p<<1|1
#define ll long long
#define fo(i,x,y) for(register int i=x;i<=y;++i)
#define go(i,x,y) for(register int i=x;i>=y;--i)
using namespace std;
inline int read(){ int x=0,fh=1; char ch=getchar(); while(!isdigit(ch)){ if(ch=='-') fh=-1; ch=getchar(); } while(isdigit(ch)){ x=(x<<1)+(x<<3)+ch-'0'; ch=getchar(); } return x*fh; }

//建树->dfs1预处理出必备信息(siz,dep,f,son)->dfs2进行轻重链剖分(求出每一个点所在重链的链头结点以及dfs序)
//套一棵线段树 
const int maxn=1e5+5;
struct Edge{
    int to,next;
}e[maxn<<1];
int tot,head[maxn],n,m,val[maxn];

void connect(int x,int y){
    e[++tot]=(Edge){y,head[x]};
    head[x]=tot; 
}

int f[maxn],dep[maxn],siz[maxn],son[maxn];

void dfs1(int now,int fa){
    f[now]=fa;
    dep[now]=dep[fa]+1;
    siz[now]=1;
    int mx=0;
    for(int i=head[now];i;i=e[i].next){
        int p=e[i].to;
        if(p==fa) continue;
        dfs1(p,now);
        siz[now]+=siz[p];
        if(siz[p]>mx){
            mx=p;
            son[now]=p;
        }
    }
} 

int dfn[maxn],t,pos[maxn],top[maxn];

void dfs2(int now,int chain){
    top[now]=chain;
    dfn[now]=++t;
    pos[t]=now;
    if(son[now]) dfs2(son[now],chain);
    for(int i=head[now];i;i=e[i].next){
        int p=e[i].to;
        if(p==f[now]||p==son[now]) continue;
        dfs2(p,p);
    }
}

struct Node{
    int Lef,Rig;
    ll tag,val;
}tree[maxn<<2];

void push_up(int now){
    tree[now].val=tree[ls(now)].val+tree[rs(now)].val;
}

void push_down(int now){
    int lt=ls(now),rt=rs(now);
    tree[lt].tag+=tree[now].tag;
    tree[lt].val+=(tree[lt].Rig-tree[lt].Lef+1)*tree[now].tag;
    tree[rt].tag+=tree[now].tag;
    tree[rt].val+=(tree[rt].Rig-tree[rt].Lef+1)*tree[now].tag;
    tree[now].tag=0;
}

void build(int now,int L,int R){
    tree[now].Lef=L,tree[now].Rig=R;
    if(L==R){
        tree[now].val=val[pos[L]];
        return;
    }
    int mid=(L+R)>>1;
    build(ls(now),L,mid);
    build(rs(now),mid+1,R);
    push_up(now);
}

void update(int now,int aim_L,int aim_R,ll k){
    if(tree[now].Lef>=aim_L&&tree[now].Rig<=aim_R){
        tree[now].tag+=k;
        tree[now].val+=(tree[now].Rig-tree[now].Lef+1)*k;
        return;
    }
    if(tree[now].tag) push_down(now);
    int mid=(tree[now].Lef+tree[now].Rig)>>1;
    if(aim_L<=mid) update(ls(now),aim_L,aim_R,k);
    if(aim_R>mid) update(rs(now),aim_L,aim_R,k);
    push_up(now);
}

ll ask(int now,int aim_L,int aim_R){
    if(tree[now].Lef>=aim_L&&tree[now].Rig<=aim_R) return tree[now].val;
    int mid=(tree[now].Lef+tree[now].Rig)>>1;
    ll ret=0;
    if(tree[now].tag) push_down(now);
    if(aim_L<=mid) ret+=ask(ls(now),aim_L,aim_R);
    if(aim_R>mid) ret+=ask(rs(now),aim_L,aim_R);
    return ret; 
}

void change_point(int now,ll k){
    update(1,dfn[now],dfn[now],k);
}

void change_subtree(int now,ll k){
    update(1,dfn[now],dfn[now]+siz[now]-1,k);
}

ll ask_chain(int now){
    ll ret=0;
    while(dep[top[now]]>1){
        ret+=ask(1,dfn[top[now]],dfn[now]);
        now=f[top[now]];
    }
    ret+=ask(1,1,dfn[now]);
    return ret;
}

int main(){
    n=read(),m=read();
    fo(i,1,n) val[i]=read();
    fo(i,1,n-1){
        int x=read(),y=read();
        connect(x,y);
        connect(y,x);
    }
    dfs1(1,0);
    dfs2(1,1);
    build(1,1,n);
    fo(i,1,m){
        int opt=read(),x=read();
        if(opt==1){
            int k=read();
            change_point(x,k);
        }
        if(opt==2){
            int k=read();
            change_subtree(x,k);
        }
        if(opt==3){
            printf("%lld\n",ask_chain(x));
        }
    }
    return 0;
}
2020/10/12 22:06
加载中...