HDU-5759 Gardener Bo(线段树+分类讨论)

Gardener Bo

Time Limit: 16000/8000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others)
Total Submission(s): 182    Accepted Submission(s): 67


Problem Description
Gardener Bo loves Trees.Now he asks you to help him take care of his lovely tree.

A rooted tree with root=1 is given.Every node on the tree has a value wi .Let fa[u] be the father of u .

Let LCA(u,v) be the least common ancestor of u and v .The expression [condition] is 1 when condition is True,is 0 when condition is False.

Define

f(u)=i=1nj=in(wi+wj)[LCA(i,j)=u]


Now there are Q events happening.Each event has one of two types:

1 u x :pick out all v that satisfies v=u or fa[v]=u or fa[fa[v]]=u ,and add x to wv .

2 u :query f(u)mod232 .
 

Input
There are several test cases.

The first line contains two integers n,Q .

The second line contains n1 integers,i-th indicates fa[i+1] .

The third line contains n integers,the i-th indicates the initial wi .

Following Q lines each describes an event.

1n,Q3×105,|wi|,|x|<109
 

Output
For every event with type 2,you should print a number indicating the answer.
 

Sample Input
  
  
5 3 1 1 3 3 -5 2 0 7 -6 1 5 2 2 3 2 2 10 5 1 2 3 3 1 2 6 2 2 -2 5 8 -6 0 -4 6 6 8 9 2 10 1 3 4 1 6 -2 2 9 2 4
  
  

题意:一棵树有n个节点,以1为根节点,每个节点有权值wi,定义f(u)为以u为根的子树中,LCA(u,v)=u的所有点对的权值和

有2种操作:

①选择点u,将u点以及它的子节点和孙子节点的权值都加上x

②查询f(u)

题解:具体的公式上面也给出了,最好对照的推一下公式。

其实对于1,2,3部分没必要用线段树维护,考虑到除了x都是常量,因此每次更新的时候只要打上标记:add[u]+=x,查询的时候加来就行。

对于第4部分,用树链剖分维护即可。每次更新点u,对于它的祖先中轻链上的点直接单点更新(轻链上的点的个数不超过logN个),然后由于一个节点只有1条重链,只要用树剖+线段树维护每个点对重链上的点的贡献即可。

#include<bits/stdc++.h>
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
using namespace std;
typedef long long LL;
typedef unsigned int UI;
const int MX = 3e5 + 5;
const int inf = 0x3f3f3f3f;
struct Edge{
    int v,nxt;
}E[MX*2];
int head[MX],tot;
int n,m;
int fa[MX],son[MX],top[MX];
int dfn[MX],out[MX],dfp;
UI f[MX],c[MX],w[MX];
UI sz[MX],cnt_son1[MX],cnt_son2[MX];
UI add[MX],sum[MX<<2];

void init(){
    memset(add,0,sizeof(add));
    memset(sum,0,sizeof(sum));
    memset(head,-1,sizeof(head));
    tot=dfp=0;
}
void add_edge(int u,int v){
    E[tot].v=v;
    E[tot].nxt=head[u];
    head[u]=tot++;
}
void dfs1(int u){
    cnt_son1[u]=cnt_son2[u]=son[u]=c[u]=0;
    sz[u]=1;
    for(int i=head[u];~i;i=E[i].nxt){
        int v=E[i].v;
        if(v==fa[u]) continue;
        dfs1(v);
        sz[u]+=sz[v];
        cnt_son1[u]++;
        cnt_son2[u]+=cnt_son1[v]+1;
        c[u]+=sz[v]*cnt_son1[v];
        if(sz[son[u]]<sz[v]) son[u]=v;
    }
    f[u]=w[u]*(sz[u]+1);
    for(int i=head[u];~i;i=E[i].nxt){
        int v=E[i].v;
        if(v==fa[u]) continue;
        f[u]+=(sz[u]-sz[v])*w[v];
        w[u]+=w[v];

    }
}
void dfs2(int u,int t){
    top[u]=t;
    dfn[u]=++dfp;
    if(son[u]) dfs2(son[u],t);
    for(int i=head[u];~i;i=E[i].nxt){
        int v=E[i].v;
        if(v==son[u]||v==fa[u]) continue;
        dfs2(v,v);
    }
    out[u]=dfp;
}

void update(int x,UI val){
    while(top[x]!=top[1]){
        int v=top[x],u=fa[v];
        f[u]+=(sz[u]-sz[v])*val;
        x=u;
    }
}
void Update(int p,UI val,int l,int r,int rt){
    sum[rt]+=val;
    if(l==r) return;
    int m=(l+r)>>1;
    if(p<=m) Update(p,val,lson);
    else Update(p,val,rson);
}
UI query(int L,int R,int l,int r,int rt){
    if(L<=l&&R>=r) return sum[rt];
    int m=(l+r)>>1;
    UI ret=0;
    if(L<=m) ret+=query(L,R,lson);
    if(R>m) ret+=query(L,R,rson);
    return ret;
}
void solve(){
    init();
    for(int i=2;i<=n;i++) {
        scanf("%d",&fa[i]);
        add_edge(fa[i],i);add_edge(i,fa[i]);
    }
    for(int i=1;i<=n;i++) scanf("%u",&w[i]);
    dfs1(1);
    dfs2(1,1);
    while(m--){
        int op,u;
        UI x;
        scanf("%d",&op);
        if(op==1){
            scanf("%d%u",&u,&x);
            add[u]+=x;
            update(u,x*(1+cnt_son2[u]));
            Update(dfn[u],x*(1+cnt_son2[u]),1,n,1);
        }
        else{
            scanf("%d",&u);
            UI ans=f[u];
            ans+=add[u]*(2+sz[u]*cnt_son2[u]-c[u]);
            if(fa[u]) ans+=add[fa[u]]*(2+sz[u]*cnt_son1[u]);
            if(fa[fa[u]]) ans+=add[fa[fa[u]]]*(1+sz[u]);
            if(son[u]) { //son[u]存在表示u是重链上的
                ans+=(sz[u]-sz[son[u]])*query(dfn[son[u]],out[son[u]],1,n,1);
            }
            printf("%u\n",ans);
        }
    }
}
int main(){
    //freopen("in.txt","r",stdin);
    while(~scanf("%d%d",&n,&m)) solve();
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值