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

来源:互联网 发布:珠海知未科技有限公司 编辑:程序博客网 时间:2024/05/29 19:44

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.Letfa[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:queryf(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 31 1 3 3-5 2 0 7 -61 5 22 32 210 51 2 3 3 1 2 6 2 2 -2 5 8 -6 0 -4 6 6 8 92 101 3 41 6 -22 92 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|1using 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;}


阅读全文
0 0
原创粉丝点击