hdu5759 线段树+树剖

题解已经放出来了,可以推一下上面的公式。关键这题要维护很多信息,当发生一次修改节点u,我们需要用两颗线段树分别维护u的孩子层和u的孙子层,由于是区间修改,所以需要使用bfs序才能使这些点连续。对于修改u,就直接改好了,最后麻烦的是要修改从u的父亲到根的整条链,用树剖改整条链可以吗?显然不可以。。。因为size(v)-size(w)是变化的,那么从另一个角度考虑,对于某个节点v,遍历所有孩子,对于每个孩子w,size(v)-size(w)是固定的,那么我们只要知道这个w孩子被修改增加的权值就可以了,也就是我们只需要记录x*(son2[u]+1)的累加值,那么对于修改u,我们只需要用树剖更新u到根的x*(son2[u]+1)就可以了,但是每次询问,需要遍历所有的孩子,才能知道size(v)-size(w),这样复杂度要炸,但是我们知道每个节点只有一个重儿子,如果轻儿子直接更新答案到父亲,那么每次询问只要查重儿子就可以了,于是可以沿着top往上,直接修改轻儿子对父亲的贡献。这样就可以了。。。然而这题显然可以不用树剖来维护来,直接用线段树,单点更新+区间和查询,就可以完成对u到根的更新,直接修改u,查询的时候只要查子树之和,因为只有子树才会改动查询点。。。


#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<vector>
#include<set>
#include<queue>
#include<algorithm>
#define ll long long
#define Maxn 300010
#define ls id<<1,l,mid
#define rs id<<1|1,mid+1,r
using namespace std;

inline int read(){
    int x=0,f=1;
    char ch=getchar();
    while(ch<'0'||ch>'9'){
        if(ch=='-') f=-1;
        ch=getchar();
    }
    while(ch>='0'&&ch<='9'){
        x=x*10+ch-'0';
        ch=getchar();
    }
    return x*f;
}
struct edge{
    int to,next;
}p[Maxn];
int tot;
int head[Maxn],w[Maxn];
void addedge(int u,int v){
    p[tot].to=v;
    p[tot].next=head[u];
    head[u]=tot++;
}
int sz[Maxn],s[Maxn],s1[Maxn],s2[Maxn],f[Maxn],g[Maxn],son[Maxn],fa[Maxn];
int dl[Maxn],dr[Maxn];
int tim;
void dfs(int u){
    dl[u]=++tim;
    sz[u]=1;
    s[u]=f[u]=w[u];
    s1[u]=s2[u]=g[u]=son[u]=0;
    for(int i=head[u];~i;i=p[i].next){
        int v=p[i].to;
        dfs(v);
        sz[u]+=sz[v];
        s[u]+=s[v];
        s1[u]++;
        s2[u]+=s1[v]+1;
        f[u]-=sz[v]*s[v];
        g[u]-=sz[v]*s1[v];
        if(sz[v]>sz[son[u]]) son[u]=v;
    }
    f[u]+=sz[u]*s[u];
    g[u]+=2+sz[u]*s2[u];
    dr[u]=tim;
}
int top[Maxn];
void dfs1(int u,int pre){
    top[u]=pre;
    if(son[u]) dfs1(son[u],pre);
    for(int i=head[u];~i;i=p[i].next){
        int v=p[i].to;
        if(v!=son[u]) dfs1(v,v);
    }
}
int e,n;
int q[Maxn],dfn[Maxn],bl[Maxn],br[Maxn],bL[Maxn],bR[Maxn];
void bfs(int u){
    q[e=1]=u;
    for(int i=1;i<=e;i++){
        int v=q[i];
        dfn[v]=i;
        bl[v]=e+1;
        for(int j=head[v];~j;j=p[j].next)
            q[++e]=p[j].to;
        br[v]=e;
        if(bl[v]>br[v]) bl[v]=n+1,br[v]=0;
    }
    for(int i=1;i<=e;i++){
        int v=q[i];
        bL[v]=n+1,bR[v]=0;
        for(int j=head[v];~j;j=p[j].next){
            bL[v]=min(bL[v],bl[p[j].to]);
            bR[v]=max(bR[v],br[p[j].to]);
        }
    }
}
int tr[Maxn<<2][3];
void pushup(int id){
    tr[id][2]=tr[id<<1][2]+tr[id<<1|1][2];
}
void build(int id,int l,int r){
    tr[id][0]=tr[id][1]=tr[id][2]=0;
    if(l==r) return;
    int mid=l+r>>1;
    build(ls);
    build(rs);
}
void update(int id,int l,int r,int a,int b,int c,int d){
    if(a<=l&&r<=b){
        tr[id][d]+=c;
        return;
    }
    int mid=l+r>>1;
    if(a<=mid) update(ls,a,b,c,d);
    if(b>mid) update(rs,a,b,c,d);
}
void modify(int id,int l,int r,int a,int b){
    if(l==r){
        tr[id][2]+=b;
        return;
    }
    int mid=l+r>>1;
    if(a<=mid) modify(ls,a,b);
    else modify(rs,a,b);
    pushup(id);
}
int d0,d1,d2;
void query(int id,int l,int r,int a){
    d0+=tr[id][0];
    d1+=tr[id][1];
    if(l==r) return;
    int mid=l+r>>1;
    if(a<=mid) query(ls,a);
    else query(rs,a);
}
int query(int id,int l,int r,int a,int b){
    if(a<=l&&r<=b) return tr[id][2];
    int mid=l+r>>1;
    int ans=0;
    if(a<=mid) ans+=query(ls,a,b);
    if(b>mid) ans+=query(rs,a,b);
    return ans;
}
int main()
{
    int Q,u,x,op;
    while(~scanf("%d%d",&n,&Q)){
        tot=0;
        memset(head,-1,sizeof head);
        for(int i=2;i<=n;i++){
            fa[i]=read();
            addedge(fa[i],i);
        }
        for(int i=1;i<=n;i++) w[i]=read();
        tim=0;
        dfs(1);
        bfs(1);
        dfs1(1,1);
        build(1,1,n);
        while(Q--){
            op=read();
            if(op==1){
                u=read(),x=read();
                if(bL[u]!=n+1) update(1,1,n,bL[u],bR[u],x,0);
                if(bl[u]!=n+1) update(1,1,n,bl[u],br[u],x,1);
                f[u]+=x*g[u];
                x*=s2[u]+1;
                modify(1,1,n,dl[u],x);
                while(top[u]!=1){
                    u=top[u];
                    f[fa[u]]+=x*(sz[fa[u]]-sz[u]);
                    u=fa[u];
                }
            }
            else{
                u=read();
                d0=d1=d2=0;
                query(1,1,n,dfn[u]);
                if(son[u]) d2=query(1,1,n,dl[son[u]],dr[son[u]]);
                unsigned ans=f[u]+d0*(sz[u]+1)+d1*(2+sz[u]*s1[u])+d2*(sz[u]-sz[son[u]]);
                printf("%u\n",ans);
            }
        }
    }
    return 0;
}




猜你喜欢

转载自blog.csdn.net/u012866104/article/details/52050283