bzoj 4034 [HAOI2015] T2(树链剖分,线段树)

4034: [HAOI2015]T2

Time Limit: 10 Sec  Memory Limit: 256 MB
Submit: 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

Sample Output

6
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 }
View Code
原文地址:https://www.cnblogs.com/lidaxin/p/5186522.html