题目描述
有一棵点数为 N 的树,以点 1 为根,且树点有边权。然后有 M 个操作,分为三种:
操作 1 :把某个节点 x 的点权增加 a 。
操作 2 :把某个节点 x 为根的子树中所有点的点权都增加 a 。
操作 3 :询问某个节点 x 到根的路径中所有点的点权和。
输入输出格式
输入格式:第一行包含两个整数 N, M 。表示点数和操作数。接下来一行 N 个整数,表示树中节点的初始权值。接下来 N-1 行每行两个正整数 from, to , 表示该树中存在一条边 (from, to) 。再接下来 M 行,每行分别表示一次操作。其中第一个数表示该操作的种类( 1-3 ) ,之后接这个操作的参数( x 或者 x a ) 。
输出格式:对于每个询问操作,输出该询问的答案。答案之间用换行隔开。
输入输出样例
说明
对于 100% 的数据, N,M<=100000 ,且所有输入数据的绝对值都不
会超过 10^6 。
题解
先剖一下。
操作1:在dfn[x]处+=a
操作2:从dfn[x]到dfn[x]+siz[x]-1上区间+a
操作3:往上跳的同时ans+=find(dfn[top[x]],dfn[x])
几乎是阉割版的树剖了。
1 /* 2 qwerta 3 P3178 [HAOI2015]树上操作 4 Accepted 5 100 6 代码 C++,2.93KB 7 提交时间 2018-09-11 17:00:43 8 耗时/内存 9 993ms, 24476KB 10 */ 11 #include<cstdio> 12 #include<iostream> 13 using namespace std; 14 #define LL long long 15 const LL MAXN=100000+7; 16 LL val[MAXN]; 17 struct emm{ 18 LL e,f; 19 }b[2*MAXN]; 20 LL h[MAXN]; 21 LL tot=0; 22 void con(LL x,LL y) 23 { 24 b[++tot].f=h[x]; 25 h[x]=tot; 26 b[tot].e=y; 27 b[++tot].f=h[y]; 28 h[y]=tot; 29 b[tot].e=x; 30 return; 31 } 32 LL d[MAXN],siz[MAXN],z[MAXN],fa[MAXN],top[MAXN]; 33 void dfs(LL x) 34 { 35 siz[x]=1,top[x]=x; 36 LL mac=0,macc=-1; 37 for(LL i=h[x];i;i=b[i].f) 38 if(!d[b[i].e]) 39 { 40 d[b[i].e]=d[x]+1; 41 fa[b[i].e]=x; 42 dfs(b[i].e); 43 siz[x]+=siz[b[i].e]; 44 if(macc<siz[b[i].e]){mac=b[i].e,macc=siz[b[i].e];} 45 } 46 z[x]=mac; 47 top[mac]=x; 48 return; 49 } 50 LL q[MAXN],dfn[MAXN]; 51 void dfss(LL x) 52 { 53 q[++tot]=x; 54 dfn[x]=tot; 55 if(z[x])dfss(z[x]); 56 for(LL i=h[x];i;i=b[i].f) 57 if(fa[b[i].e]==x&&b[i].e!=z[x]) 58 dfss(b[i].e); 59 return; 60 } 61 LL fitop(LL x) 62 { 63 if(top[x]==x)return x; 64 return top[x]=fitop(top[x]); 65 } 66 struct ahh{ 67 LL l,r,mid; 68 long long v,laz; 69 }a[8*MAXN]; 70 #define lz (i<<1) 71 #define rz ((i<<1)|1) 72 #define amid a[i].mid 73 void build(LL i,LL ll,LL rr) 74 { 75 a[i].l=ll; 76 a[i].r=rr; 77 if(ll==rr){a[i].v=val[q[ll]];return;} 78 amid=(ll+rr)>>1; 79 build(lz,ll,amid); 80 build(rz,amid+1,rr); 81 a[i].v=a[lz].v+a[rz].v; 82 return; 83 } 84 void add(LL i,LL ll,LL rr,LL k) 85 { 86 if(a[i].l==ll&&a[i].r==rr){a[i].laz+=k;return;} 87 a[i].v+=(rr-ll+1)*k; 88 if(rr<=amid)add(lz,ll,rr,k); 89 else if(amid+1<=ll)add(rz,ll,rr,k); 90 else {add(lz,ll,amid,k);add(rz,amid+1,rr,k);} 91 return; 92 } 93 long long ans=0; 94 void pushtag(LL i) 95 { 96 if(!a[i].laz)return; 97 a[i].v+=(a[i].r-a[i].l+1)*a[i].laz; 98 if(a[i].l==a[i].r){a[i].laz=0;return;} 99 a[lz].laz+=a[i].laz; 100 a[rz].laz+=a[i].laz; 101 a[i].laz=0; 102 return; 103 } 104 void find(LL i,LL ll,LL rr) 105 { 106 pushtag(i); 107 if(a[i].l==ll&&a[i].r==rr){ans+=a[i].v;return;} 108 if(rr<=amid)find(lz,ll,rr); 109 else if(amid+1<=ll)find(rz,ll,rr); 110 else {find(lz,ll,amid);find(rz,amid+1,rr);} 111 return; 112 } 113 LL s; 114 int main() 115 { 116 //freopen("a.in","r",stdin); 117 LL n,m; 118 scanf("%lld%lld",&n,&m); 119 for(LL i=1;i<=n;++i) 120 scanf("%lld",&val[i]); 121 for(LL i=1;i<n;++i) 122 { 123 LL u,v; 124 scanf("%lld%lld",&u,&v); 125 con(u,v); 126 } 127 s=1; 128 d[s]=1; 129 dfs(s); 130 tot=0; 131 dfss(s); 132 for(LL i=1;i<=n;++i) 133 top[i]=fitop(i); 134 build(1,1,n); 135 for(LL i=1;i<=m;++i) 136 { 137 LL opt; 138 scanf("%lld",&opt); 139 if(opt==1) 140 { 141 LL x,v; 142 scanf("%lld%lld",&x,&v); 143 add(1,dfn[x],dfn[x],v); 144 } 145 else if(opt==2) 146 { 147 LL x,v; 148 scanf("%lld%lld",&x,&v); 149 add(1,dfn[x],dfn[x]+siz[x]-1,v); 150 } 151 else 152 { 153 LL x; 154 scanf("%lld",&x); 155 ans=0; 156 while(x) 157 { 158 find(1,dfn[top[x]],dfn[x]); 159 x=fa[top[x]]; 160 } 161 printf("%lld\n",ans); 162 } 163 } 164 return 0; 165 }