bzoj4034:[HAOI2015]树上操作
Description
有一棵点数为 N 的树,以点 1 为根,且树点有边权。然后有 M 个
操作,分为三种:
操作 1 :把某个节点 x 的点权增加 a 。
操作 2 :把某个节点 x 为根的子树中所有点的点权都增加 a 。
操作 3 :询问某个节点 x 到根的路径中所有点的点权和。
Input
第一行包含两个整数 N, M 。表示点数和操作数。接下来一行 N 个整数,表示树中节点的初始权值。接下来 N-1
行每行三个正整数 fr, to , 表示该树中存在一条边 (fr, to) 。再接下来 M 行,每行分别表示一次操作。其中
第一个数表示该操作的种类( 1-3 ) ,之后接这个操作的参数( x 或者 x a ) 。
Output
对于每个询问操作,输出该询问的答案。答案之间用换行隔开。
Sample Input
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 2 3 4 5
1 2
1 4
2 3
2 5
3 3
1 2 1
3 5
2 1 2
3 3
Sample Output
6
9
13
9
13
HINT
对于 100% 的数据, N,M<=100000 ,且所有输入数据的绝对值都不会超过 10^6 。
题解:
明明就是一道树链剖分模板题啊啊啊啊……
RE了无数次,简直是醉了,最后发现……有一个数组名是rank,大概是和库中某个函数名重了,改成rk就AC了……
好吧,言归正传
操作1对应到线段树中的单点修改
操作2因为以某节点为根的子树的编号都应该是连续的,所以可以对应到线段树中的区间修改
之前求重子时不是记过一个size吗,在这里就可以用来知道子树编号的范围
操作3比较常规,求路径上的和
还有中间求和操作要开long long,否则也会RE
注意:就是容器名称呵,最好有“个性”一些,千万不要和其他东西重了
代码:
1 #include<iostream> 2 #include<cstdio> 3 using namespace std; 4 5 const int MAXN=200005; 6 struct node 7 { 8 int v; 9 node *next; 10 }pool[MAXN],*h[MAXN]; 11 int cnt,tot; 12 int fa[MAXN],dep[MAXN],size[MAXN],son[MAXN]; 13 int rk[MAXN],w[MAXN],top[MAXN],val[MAXN]; 14 15 void addedge(int u,int v) 16 { 17 node *p=&pool[++cnt],*q=&pool[++cnt]; 18 p->v=v;p->next=h[u];h[u]=p; 19 q->v=u;q->next=h[v];h[v]=q; 20 } 21 void dfs1(int u) 22 { 23 int v; 24 size[u]=1; 25 int Bson=0,sonnum=0; 26 for(node *p=h[u];p;p=p->next) 27 if(fa[u]!=(v=p->v)) 28 { 29 fa[v]=u; 30 dep[v]=dep[u]+1; 31 dfs1(v); 32 size[u]+=size[v]; 33 if(size[v]>Bson) Bson=size[v],sonnum=v; 34 } 35 son[u]=sonnum; 36 } 37 void dfs2(int u) 38 { 39 int v=son[u]; 40 if(v) 41 { 42 top[v]=top[u]; 43 rk[v]=++tot; 44 w[rk[v]]=val[v]; 45 dfs2(v); 46 } 47 for(node *p=h[u];p;p=p->next) 48 if(fa[v=p->v]==u && v!=son[u]) 49 { 50 top[v]=v; 51 rk[v]=++tot; 52 w[rk[v]]=val[v]; 53 dfs2(v); 54 } 55 } 56 57 struct tree 58 { 59 int l,r; 60 long long sum,lazy; 61 tree *left,*right; 62 }t[4*MAXN],*root; 63 int cnt1; 64 void pushdown(tree *p) 65 { 66 if(p->lazy) 67 { 68 p->sum+=p->lazy*(long long)(p->r-p->l+1); 69 if(p->left) p->left->lazy+=p->lazy; 70 if(p->right) p->right->lazy+=p->lazy; 71 p->lazy=0; 72 } 73 } 74 void update(tree *p) 75 { 76 p->sum=0; 77 if(p->left) p->sum+=p->left->sum+p->left->lazy*(long long)(p->left->r-p->left->l+1); 78 if(p->right) p->sum+=p->right->sum+p->right->lazy*(long long)(p->right->r-p->right->l+1); 79 } 80 void Build_Tree(tree *p,int l,int r) 81 { 82 p->l=l;p->r=r; 83 if(l==r) 84 { 85 p->sum=(long long)w[l]; 86 return; 87 } 88 int mid=(l+r)/2; 89 p->left=&t[++cnt1];p->right=&t[++cnt1]; 90 Build_Tree(p->left,l,mid); 91 Build_Tree(p->right,mid+1,r); 92 p->sum=p->left->sum+p->right->sum; 93 } 94 void change(tree *p,int l,int r,int c) 95 { 96 if(p->l==l && p->r==r) 97 { 98 p->lazy+=(long long)c; 99 return; 100 } 101 pushdown(p); 102 if(p->left->r>=r) change(p->left,l,r,c); 103 else if(p->right->l<=l) change(p->right,l,r,c); 104 else change(p->left,l,p->left->r,c),change(p->right,p->right->l,r,c); 105 update(p); 106 } 107 long long query(tree *p,int l,int r) 108 { 109 if(p->l==l && p->r==r) 110 return p->sum+p->lazy*(p->r-p->l+1); 111 pushdown(p); 112 if(p->left->r>=r) return query(p->left,l,r); 113 else if(p->right->l<=l) return query(p->right,l,r); 114 else return query(p->left,l,p->left->r)+query(p->right,p->right->l,r); 115 } 116 117 long long Sum(int x,int y) 118 { 119 long long ret=0; 120 int f1=top[x],f2=top[y]; 121 while(f1!=f2) 122 { 123 if(dep[f1]<dep[f2]) swap(f1,f2),swap(x,y); 124 ret+=query(root,rk[f1],rk[x]); 125 x=fa[f1];f1=top[x]; 126 } 127 if(dep[x]>dep[y]) swap(x,y); 128 ret+=query(root,rk[x],rk[y]); 129 return ret; 130 } 131 132 int main() 133 { 134 int n,m,i,a,b,c; 135 scanf("%d%d",&n,&m); 136 for(i=1;i<=n;i++) scanf("%d",&val[i]); 137 for(i=1;i<n;i++) 138 scanf("%d%d",&a,&b),addedge(a,b); 139 140 dfs1(1); 141 top[1]=1;rk[1]=++tot;w[rk[1]]=val[1]; 142 dfs2(1); 143 root=&t[++cnt1];Build_Tree(root,1,n); 144 145 while(m --> 0) 146 { 147 scanf("%d",&c); 148 if(c==1) 149 scanf("%d%d",&a,&b),change(root,rk[a],rk[a],b); 150 else if(c==2) 151 scanf("%d%d",&a,&b),change(root,rk[a],rk[a]+size[a]-1,b); 152 else 153 scanf("%d",&a),printf("%lld\n",Sum(1,a)); 154 } 155 156 return 0; 157 }
既然选择了远方,便只顾风雨兼程