• [HAOI2015]树上操作


    题目描述

    有一棵点数为 N 的树,以点 1 为根,且树点有边权。然后有 M 个操作,分为三种:操作 1 :把某个节点 x 的点权增加 a 。操作 2 :把某个节点 x 为根的子树中所有点的点权都增加 a 。操作 3 :询问某个节点 x 到根的路径中所有点的点权和。

    输入输出格式

    输入格式:

    第一行包含两个整数 N, M 。表示点数和操作数。接下来一行 N 个整数,表示树中节点的初始权值。接下来 N-1 行每行三个正整数 fr, to , 表示该树中存在一条边 (fr, to) 。再接下来 M 行,每行分别表示一次操作。其中第一个数表示该操作的种类( 1-3 ) ,之后接这个操作的参数( x 或者 x a ) 。

    输出格式:

    对于每个询问操作,输出该询问的答案。答案之间用换行隔开。

    输入输出样例

    输入样例#1:
    5 5
    1 2 3 4 5
    1 2
    1 4
    2 3
    2 5
    3 3
    1 2 1
    3 5
    2 1 2
    3 3
    输出样例#1:
    6
    9
    13

    说明

    对于 100% 的数据, N,M<=100000 ,且所有输入数据的绝对值都不

    会超过 10^6 。

    树链剖分。

    代码实现:

     1 #include<cstdio>
     2 #include<iostream>
     3 #define ls k*2
     4 #define rs k*2+1
     5 #define LL long long
     6 #define maxn 100010
     7 using namespace std;
     8 LL a,b,c,ans;
     9 LL n,m,l,hs,nl;
    10 LL s[maxn],h[maxn];
    11 LL k[maxn],f[maxn],d[maxn],p[maxn],sz[maxn],is[maxn],ct[maxn];
    12 struct node{LL s,n;}e[maxn<<1];
    13 struct tree{LL l,r,s,f;}t[maxn<<2];
    14 inline void add(LL x,LL y){e[++hs]=(node){y,h[x]};h[x]=hs;}
    15 void dfs1(LL x,LL y,LL st){
    16     f[x]=y;d[x]=st;sz[x]=1;
    17     for(LL i=h[x];i;i=e[i].n)
    18     if(e[i].s!=y){
    19         dfs1(e[i].s,x,st+1);
    20         sz[x]+=sz[e[i].s];
    21         if(sz[e[i].s]>sz[is[x]]) is[x]=e[i].s;
    22     }
    23 }
    24 void dfs2(LL x){
    25     s[++l]=k[x];p[x]=l;
    26     if(is[x]){
    27         ct[is[x]]=ct[x];
    28         dfs2(is[x]);
    29     }
    30     for(LL i=h[x];i;i=e[i].n)
    31     if(e[i].s!=f[x]&&e[i].s!=is[x]){
    32         ct[e[i].s]=e[i].s;
    33         dfs2(e[i].s);
    34     }
    35 }
    36 void build(LL k,LL l,LL r){
    37     t[k].l=l;t[k].r=r;
    38     if(l==r){t[k].s=s[++nl];return;}
    39     LL mid=(l+r)>>1;
    40     build(ls,l,mid);
    41     build(rs,mid+1,r);
    42     t[k].s=t[ls].s+t[rs].s;
    43 }
    44 void heritage(LL k){
    45     t[ls].s+=(t[ls].r-t[ls].l+1)*t[k].f,t[ls].f+=t[k].f;
    46     t[rs].s+=(t[rs].r-t[rs].l+1)*t[k].f,t[rs].f+=t[k].f;
    47     t[k].f=0;
    48 }
    49 void change(LL k,LL l,LL r,LL al,LL ar,LL am){
    50     if(l==al&&r==ar){t[k].f+=am,t[k].s+=(r-l+1)*am;return;}
    51     if(t[k].f) heritage(k);
    52     LL mid=(l+r)>>1;
    53     if(al<=mid) change(ls,t[ls].l,t[ls].r,al,min(ar,mid),am);
    54     if(ar>mid) change(rs,t[rs].l,t[rs].r,max(al,mid+1),ar,am);
    55     t[k].s=t[ls].s+t[rs].s;
    56 }
    57 LL query(LL k,LL l,LL r,LL al,LL ar){
    58     if(l==al&&r==ar) return t[k].s;
    59     if(t[k].f) heritage(k);
    60     LL mid=(l+r)>>1,ans=0;
    61     if(al<=mid) ans+=query(ls,t[ls].l,t[ls].r,al,min(ar,mid));
    62     if(ar>mid) ans+=query(rs,t[rs].l,t[rs].r,max(al,mid+1),ar);
    63     return ans;
    64 }
    65 int main(){
    66     scanf("%lld%lld",&n,&m);
    67     for(LL i=1;i<=n;i++) scanf("%lld",&k[i]);
    68     for(LL i=1;i<n;i++){scanf("%lld%lld",&a,&b);add(a,b);add(b,a);}
    69     dfs1(1,0,1);
    70     ct[1]=1;
    71     dfs2(1);
    72     build(1,1,l);
    73     while(m--){
    74         scanf("%lld%lld",&a,&b);
    75         if(a==1){
    76             scanf("%lld",&c);
    77             change(1,1,l,p[b],p[b],c);
    78             
    79         }
    80         if(a==2){
    81             scanf("%lld",&c);
    82             change(1,1,l,p[b],p[b]+sz[b]-1,c);
    83         }
    84         if(a==3){
    85             ans=0;
    86             for(;b;b=f[ct[b]])
    87             ans+=query(1,1,l,p[ct[b]],p[b]);
    88             printf("%lld
    ",ans);
    89         }
    90     }
    91     return 0;
    92 }

    题目来源:洛谷

  • 相关阅读:
    使用 PHPMailer 发邮件
    安装phpssdb扩展:
    CI安全
    CI调试应用程序
    Sphinx的GEO距离搜索 [转载]
    Lua开发环境搭建(Mac OS X)
    MySQL 的索引和最左前缀原则
    PHP解码Json(json_decode)字符串返回NULL的原因及解决方法(转载)
    PHP连接MySQL报错"No such file or directory"的解决办法
    web 性能优化指南阅读笔记
  • 原文地址:https://www.cnblogs.com/J-william/p/6381929.html
Copyright © 2020-2023  润新知