siz[v]表示以v为根的子树的节点数
top[v]表示v所在的重链的顶端节点
fa[v]表示v的父亲
pos[v]表示v的父边标号
mx[v]表示v的子树中边的标号最大的那条边
参考:http://blog.sina.com.cn/s/blog_6974c8b20100zc61.html
题意:
有一棵点数为 N 的树,以点 1 为根,且树点有边权。然后有 M 个
操作,分为三种:
操作 1 :把某个节点 x 的点权增加 a 。
操作 2 :把某个节点 x 为根的子树中所有点的点权都增加 a 。
操作 3 :询问某个节点 x 到根的路径中所有点的点权和。
第一次写树链剖分。。
1 #include<algorithm> 2 #include<iostream> 3 #include<cstdlib> 4 #include<cstring> 5 #include<cstdio> 6 #include<cmath> 7 using namespace std; 8 9 typedef long long LL; 10 11 #define N 100010 12 13 int id; 14 int fa[N],siz[N],top[N]; 15 int head[N],pos[N],mx[N],v[N]; 16 LL sum[N<<2],add[N<<2]; 17 18 struct Node 19 { 20 int to,next; 21 }e[N<<1]; 22 int cnt; 23 24 int n,m; 25 int uu,vv; 26 27 int read() 28 { 29 int x=0,f=1;char ch=getchar(); 30 while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} 31 while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} 32 return x*f; 33 } 34 35 void link(int x,int y) 36 { 37 e[++cnt]=(Node){y,head[x]}; 38 head[x]=cnt; 39 } 40 41 void dfs(int x) 42 { 43 siz[x]=1; 44 for (int i=head[x];i;i=e[i].next) 45 if (e[i].to!=fa[x]) 46 { 47 fa[e[i].to]=x; 48 dfs(e[i].to); 49 siz[x]+=siz[e[i].to]; 50 mx[x]=max(mx[x],mx[e[i].to]); 51 } 52 } 53 54 void dfs2(int x,int cha) 55 { 56 top[x]=cha;pos[x]=mx[x]=++id; 57 int k=0; 58 for(int i=head[x];i;i=e[i].next) 59 if(e[i].to!=fa[x]&&siz[e[i].to]>siz[k]) 60 k=e[i].to; 61 if(k) 62 { 63 dfs2(k,cha);mx[x]=max(mx[x],mx[k]); 64 } 65 for(int i=head[x];i;i=e[i].next) 66 if(e[i].to!=fa[x]&&e[i].to!=k) 67 { 68 dfs2(e[i].to,e[i].to); 69 mx[x]=max(mx[x],mx[e[i].to]); 70 } 71 } 72 73 void pushup(int now) 74 { 75 sum[now]=sum[now<<1]+sum[now<<1|1]; 76 } 77 78 void pushdown(int nowl,int nowr,int now) 79 { 80 if (nowl==nowr) 81 return; 82 int mid=(nowl+nowr)>>1; 83 LL t=add[now]; 84 add[now]=0; 85 add[now<<1]+=t; 86 add[now<<1|1]+=t; 87 sum[now<<1]+=t*(mid-nowl+1); 88 sum[now<<1|1]+=t*(nowr-mid); 89 } 90 91 void update(int nowl,int nowr,int now,int l,int r,LL d) 92 { 93 if (add[now]) 94 pushdown(nowl,nowr,now); 95 if (nowl==l && nowr==r) 96 { 97 add[now]+=d; 98 sum[now]+=(nowr-nowl+1)*d; 99 return ; 100 } 101 int mid=(nowl+nowr)>>1; 102 if (l<=mid) 103 update(nowl,mid,now<<1,l,min(r,mid),d); 104 if (r>mid) 105 update(mid+1,nowr,now<<1|1,max(l,mid+1),r,d); 106 pushup(now); 107 } 108 109 LL query(int nowl,int nowr,int now,int l,int r) 110 { 111 if (add[now]) 112 pushdown(nowl,nowr,now); 113 if (nowl==l && nowr==r) 114 return sum[now]; 115 int mid=(nowl+nowr)>>1; 116 LL ans=0; 117 if (l<=mid) 118 ans+=query(nowl,mid,now<<1,l,min(mid,r)); 119 if (r>mid) 120 ans+=query(mid+1,nowr,now<<1|1,max(mid+1,l),r); 121 return ans; 122 } 123 124 LL query(int x) 125 { 126 LL ans=0; 127 while (top[x]!=1) 128 { 129 ans+=query(1,n,1,pos[top[x]],pos[x]); 130 x=fa[top[x]]; 131 } 132 ans+=query(1,n,1,1,pos[x]); 133 return ans; 134 } 135 136 int main() 137 { 138 n=read(),m=read(); 139 for (int i=1;i<=n;i++) 140 v[i]=read(); 141 for (int i=1;i<n;i++) 142 { 143 uu=read(),vv=read(); 144 link(uu,vv); 145 link(vv,uu); 146 } 147 dfs(1); 148 dfs2(1,1); 149 for (int i=1;i<=n;i++) 150 update(1,n,1,pos[i],pos[i],v[i]); 151 int askd,x,a; 152 while (m--) 153 { 154 askd=read(),x=read(); 155 if (askd==1) 156 { 157 a=read(); 158 update(1,n,1,pos[x],pos[x],a); 159 } 160 if (askd==2) 161 { 162 a=read(); 163 update(1,n,1,pos[x],mx[x],a); 164 } 165 if (askd==3) 166 printf("%lld ",query(x)); 167 } 168 return 0; 169 }