Codeforces Round #232 (Div. 1) C. On Changing Tree(树上修改一点x-di*k))

题意:
给出一棵以1为根的树,形式是从节点2开始给出每个节点的父亲节点;
然后是m次操作,操作分为两种,1 v,x,k,表示在以v为根的字数上添加,
添加的法则是看这个节点与v节点的距离为i的话,加上x-i*k;
2 v查询节点v的值。

思路一:
树链剖分,每个点保存两个值,一个是x+dep[i]*k,另外一个是k
查询的时候相当于它到根的链上(x+dep[i]*k)的和-dep[v] <script type="math/tex" id="MathJax-Element-4">*</script>(k的和)
时间复杂度:nlognlogn

思路二:
线段树,把上面的单点更新改成区间更新,单点查询就可以了,我好蠢啊

#include<bits/stdc++.h>
using namespace std;
const int N=3e5+100;
typedef pair<int,int> PI;
const int MOD=1e9+7;
int head[N],tot,deep[N];
struct Edge{
    int to,next;    
}e[N];

void init(){
    tot=0;
    memset(head,-1,sizeof(head));
}

void addedge(int from,int to){
    e[tot]=(Edge){to,head[from]};
    head[from]=tot++;
}

int son[N],siz[N],fa[N],Count=0;

void dfs1(int u,int dep){
    deep[u]=dep,son[u]=0,siz[u]=1;
    for(int i=head[u];i!=-1;i=e[i].next){
        int v=e[i].to;
        fa[v]=u;
        dfs1(v,dep+1);
        siz[u]+=siz[v];
        if(siz[v]>siz[son[u]])  son[u]=v;
    }
}

int top[N],id[N];

void dfs2(int u,int tp){
    top[u]=tp;
    id[u]=++Count;
    if(son[u]!=0)   dfs2(son[u],tp);
    for(int i=head[u];i!=-1;i=e[i].next){
        int v=e[i].to;
        if(v==son[u])   continue;
        dfs2(v,v);
    }    
}

int sum1[N*4],sum2[N*4];

void pushup(int rt){
    sum1[rt]=sum1[rt<<1]+sum1[rt<<1|1];    
    if(sum1[rt]>=MOD)   sum1[rt]-=MOD;
    sum2[rt]=sum2[rt<<1]+sum2[rt<<1|1];    
    if(sum2[rt]>=MOD)   sum2[rt]-=MOD;
}

int pos,num1,num2;
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
void update(int l,int r,int rt){
    if(l==r){
        sum1[rt]+=num1,sum2[rt]+=num2;
        if(sum1[rt]>=MOD)   sum1[rt]-=MOD;
        if(sum2[rt]>=MOD)   sum2[rt]-=MOD;
        return ;
    }
    int m=l+r>>1;
    if(pos<=m)  update(lson);
    else    update(rson);
    pushup(rt);
}

void add(PI &ans,PI tmp){
    ans.first+=tmp.first;
    if(ans.first>=MOD)  ans.first-=MOD;
    ans.second+=tmp.second;
    if(ans.second>=MOD)  ans.second-=MOD;
}

int L,R,n;
PI query(int l,int r,int rt){
   if(L<=l&&R>=r)   return (PI){sum1[rt],sum2[rt]};
    int m=l+r>>1;
    PI ans=(PI){0,0};
    if(L<=m)    add(ans,query(lson));
    if(R>m)     add(ans,query(rson));
    return ans;   
}

PI Query(int u,int v){
    int f1=top[u],f2=top[v];
    PI ans=(PI){0,0};
    while(f1!=f2){
        if(deep[f1]<deep[f2])   swap(f1,f2),swap(u,v);
        L=id[f1],R=id[u];
        add(ans,query(1,n,1));
        u=fa[f1],f1=top[u];
    }
    if(deep[u]>deep[v]) swap(u,v);
    L=id[u],R=id[v];
    add(ans,query(1,n,1));
    return ans;
}

int main(){
    int x,q,op,u,k;
    init();
    scanf("%d",&n);
    for(int i=2;i<=n;i++){
        scanf("%d",&x);
        addedge(x,i);
    }
    dfs1(1,0);
    dfs2(1,0);
    scanf("%d",&q);
    while(q--){
        scanf("%d",&op);
        if(op==1){
            scanf("%d%d%d",&u,&x,&k);
            num1=(x+1LL*deep[u]*k)%MOD,num2=k,pos=id[u];
            //printf("PPPP%d %d %d\n",id[u],num1,num2);
            update(1,n,1);
        }
        else{
            scanf("%d",&u);
            PI tmp=Query(u,1);
            //printf("%d %d\n",tmp.first,tmp.second);
            printf("%lld\n",((tmp.first-1LL*tmp.second*deep[u])%MOD+MOD)%MOD);
        }
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值