4034: [HAOI2015]T2
Time Limit: 10 Sec Memory Limit: 256 MBSubmit: 1536 Solved: 508
[Submit][Status][Discuss]
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 。
Source
【思路】
树链剖分,线段树
线段树:区间和,区间修改add
【代码】
1 #include<cstdio> 2 #include<cstring> 3 #include<vector> 4 #include<iostream> 5 #include<algorithm> 6 #define FOR(a,b,c) for(int a=(b);a<=(c);a++) 7 using namespace std; 8 9 typedef long long LL; 10 const int N = 400000+10; 11 12 struct Node { LL sum,addv; 13 }T[N<<1]; 14 15 int n,q,z,c[N]; 16 vector<int> g[N]; 17 //INIT 18 int top[N],son[N],dep[N],fa[N],siz[N],w[N],mxw[N]; 19 void dfs1(int u) { 20 son[u]=0; siz[u]=1; 21 for(int i=0;i<g[u].size();i++) { 22 int v=g[u][i]; 23 if(v!=fa[u]) { 24 fa[v]=u , dep[v]=dep[u]+1; 25 dfs1(v); 26 siz[u]+=siz[v]; 27 if(siz[v]>siz[son[u]]) son[u]=v; 28 } 29 } 30 } 31 void dfs2(int u,int tp) { 32 top[u]=tp; w[u]=mxw[u]=++z; 33 if(son[u]) 34 dfs2(son[u],tp),mxw[u]=max(mxw[u],mxw[son[u]]); 35 for(int i=0;i<g[u].size();i++) { 36 int v=g[u][i]; 37 if(v!=fa[u] && v!=son[u]) 38 dfs2(v,v),mxw[u]=max(mxw[u],mxw[v]); 39 } 40 } 41 //SEGMENT TREE 42 void pushdown(int u,int l,int r) { 43 if(T[u].addv && l<r) { 44 int lc=u<<1,rc=lc|1,M=(l+r)>>1; 45 T[lc].sum+=T[u].addv*(M-l+1); 46 T[rc].sum+=T[u].addv*(r-M); 47 T[lc].addv+=T[u].addv,T[rc].addv+=T[u].addv; 48 T[u].addv=0; 49 } 50 } 51 void update(int u,int L,int R,int l,int r,int x) { 52 pushdown(u,L,R); 53 if(l<=L && R<=r) 54 T[u].addv+=x , T[u].sum+=x*(R-L+1); 55 else { 56 int M=(L+R)>>1,lc=u<<1,rc=lc|1; 57 if(l<=M) update(lc,L,M,l,r,x); 58 if(M<r) update(rc,M+1,R,l,r,x); 59 T[u].sum=T[lc].sum+T[rc].sum; 60 } 61 } 62 LL query(int u,int L,int R,int l,int r) { 63 pushdown(u,L,R); 64 if(l<=L && R<=r) return T[u].sum; 65 else { 66 int M=(L+R)>>1; LL ans=0; 67 if(l<=M) ans+=query(u<<1,L,M,l,r); 68 if(M<r) ans+=query(u<<1|1,M+1,R,l,r); 69 return ans; 70 } 71 } 72 //Ê÷Á´ÆÊ·Ö 73 LL query(int u) { 74 LL sum=0; 75 while(top[u]!=1) { 76 sum+=query(1,1,z,w[top[u]],w[u]); 77 u=fa[top[u]]; 78 } 79 sum+=query(1,1,z,1,w[u]); 80 return sum; 81 } 82 83 void read(int& x) { 84 char c=getchar(); int f=1; x=0; 85 while(!isdigit(c)) {if(c=='-')f=-1;c=getchar();} 86 while(isdigit(c)) x=x*10+c-'0',c=getchar(); 87 x*=f; 88 } 89 int main() { 90 //freopen("in.in","r",stdin); 91 //freopen("out.in","w",stdout); 92 read(n),read(q); 93 FOR(i,1,n) read(c[i]); 94 int u,v,x,op,y; 95 FOR(i,1,n-1) { 96 read(u),read(v); 97 g[u].push_back(v); 98 g[v].push_back(u); 99 } 100 dfs1(1),dfs2(1,1); 101 FOR(i,1,n) update(1,1,z,w[i],w[i],c[i]); 102 while(q--) { 103 read(op),read(x); 104 if(op==1) 105 read(y),update(1,1,z,w[x],w[x],y); 106 else if(op==2) 107 read(y),update(1,1,z,w[x],mxw[x],y); 108 else 109 printf("%lld ",query(x)); 110 } 111 return 0; 112 }