数据结构(树链剖分):BZOJ 4034: [HAOI2015]T2

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 。

  

  1 #include <iostream>
  2 #include <cstring>
  3 #include <cstdio>
  4 #include <cstdlib>
  5 using namespace std;
  6 const int maxn=100010;
  7 int cnt,fir[maxn],to[maxn<<1],nxt[maxn<<1],n,m;
  8 void addedge(int a,int b){
  9     nxt[++cnt]=fir[a];to[cnt]=b;fir[a]=cnt;
 10 }
 11 long long key[maxn],tr[maxn<<2],add[maxn<<2];
 12 int ID[maxn],fa[maxn],top[maxn],end[maxn],sz[maxn],son[maxn];
 13 void Push_up(int x){
 14     tr[x]=tr[x<<1]+tr[x<<1|1];
 15 }
 16 void Add(int x,int l,int r,long long d){
 17     tr[x]+=(r-l+1)*d;
 18     add[x]+=d;
 19 }
 20 void Push_down(int x,int l,int r){
 21     if(add[x]){
 22         int mid=(l+r)>>1;
 23         Add(x<<1,l,mid,add[x]);
 24         Add(x<<1|1,mid+1,r,add[x]);
 25         add[x]=0;
 26     }
 27 }
 28 void Updata(int node,int l,int r,int a,int b,long long d){
 29     if(l>=a&&r<=b){
 30         Add(node,l,r,d);
 31         return;
 32     }
 33     Push_down(node,l,r);
 34     int mid=(l+r)>>1;
 35     if(mid>=a)Updata(node<<1,l,mid,a,b,d);
 36     if(mid<b) Updata(node<<1|1,mid+1,r,a,b,d);
 37     Push_up(node);
 38 }
 39 long long Query(int node,int l,int r,int a,int b){
 40     if(l>=a&&r<=b)return tr[node];
 41     Push_down(node,l,r);
 42     int mid=(l+r)>>1;
 43     long long ret=0;
 44     if(mid>=a)ret=Query(node<<1,l,mid,a,b);
 45     if(mid<b) ret+=Query(node<<1|1,mid+1,r,a,b);
 46     return ret;
 47 }
 48 void DFS(int x){
 49     sz[x]=1;
 50     for(int i=fir[x];i;i=nxt[i]){
 51         if(to[i]==fa[x])continue;
 52         fa[to[i]]=x;
 53         DFS(to[i]);
 54         sz[x]+=sz[to[i]];
 55         son[x]=sz[son[x]]<sz[to[i]]?to[i]:son[x];
 56     }
 57 }
 58 long long Solve(int y){
 59     long long ret=0;
 60     while(y){
 61         ret+=Query(1,1,n,ID[top[y]],ID[y]);
 62         y=fa[top[y]];
 63     }
 64     return ret;
 65 }
 66 int cont;
 67 void DFS2(int x,int tp){
 68     ID[x]=++cont;top[x]=tp;
 69     if(son[x])DFS2(son[x],tp);
 70     for(int i=fir[x];i;i=nxt[i])
 71         if(to[i]!=fa[x]&&to[i]!=son[x])
 72             DFS2(to[i],to[i]);
 73     end[x]=cont;
 74 }
 75 int main(){
 76     freopen("t2.in","r",stdin);
 77     freopen("t2.out","w",stdout);
 78     scanf("%d %d",&n,&m);
 79     for(int i=1;i<=n;i++)
 80         scanf("%lld",&key[i]);
 81
 82     for(int i=1,a,b;i<n;i++){
 83         scanf("%d %d",&a,&b);
 84         addedge(a,b);
 85         addedge(b,a);
 86     }
 87
 88     DFS(1);
 89     DFS2(1,1);
 90
 91     for(int i=1;i<=n;i++)
 92         Updata(1,1,n,ID[i],ID[i],key[i]);
 93     int op,x,a;
 94     while(m--){
 95         scanf("%d",&op);
 96         if(op==1){
 97             scanf("%d%d",&x,&a);
 98             Updata(1,1,n,ID[x],ID[x],a);
 99         }
100         else if(op==2){
101             scanf("%d%d",&x,&a);
102             Updata(1,1,n,ID[x],end[x],a);
103         }
104         else{
105             scanf("%d",&x);
106             printf("%lld\n",Solve(x));
107         }
108     }
109     return 0;
110 }
时间: 2024-10-07 17:01:46

数据结构(树链剖分):BZOJ 4034: [HAOI2015]T2的相关文章

BZOJ 4034: [HAOI2015]T2 树链剖分

4034: [HAOI2015]T2 Description 有一棵点数为 N 的树,以点 1 为根,且树点有边权.然后有 M 个 操作,分为三种: 操作 1 :把某个节点 x 的点权增加 a . 操作 2 :把某个节点 x 为根的子树中所有点的点权都增加 a . 操作 3 :询问某个节点 x 到根的路径中所有点的点权和. Input 第一行包含两个整数 N, M .表示点数和操作数. 接下来一行 N 个整数,表示树中节点的初始权值. 接下来 N-1 行每行三个正整数 fr, to , 表示该树

数据结构&#183;树链剖分+LCT

于是两个一起搞了... 怎么说,写的是P党风格的C++,短也不会短到哪里去,跑起来也不快,常数大成狗OTL BZOJ 1036 树链的经典题吧,点修改+路经询问 [Code] BZOJ 2243 路径修改+路径询问 [Code] BZOJ 3083 路径修改+子树询问(根可变),这道题要用树链剖分求DFS序中某一段区间的值(DFS序可查子树,链剖可修改路径,两者相结合就行了) [Code] BZOJ 2049 用LCT维护森林形态 [Code] BZOJ 2631 路径修改+路径询问+形态可变

BZOJ 4034 [HAOI2015]T2 树链剖分+线段树

题意: 一棵以1为根的树,有n个节点,m个操作. 第一种单点修改. 第二种修改一个点的子树. 第三种询问一个点到根的路径上所有点的权值和. 解析: 看到有人在做我就跑过来看了一下,看完题发现这不SB题么- - 于是就写了下,差点被出题人气死. TMD 那个 fr , to 难道就是逗我玩的? 你丫fr,to不代表有向边? 这么出题不会掉RP? 改了20分钟就这错了?你逗我? 第一种操作略 第二种操作修改子树-dfs序. 第三种链剖完之后直接找就行了. 复杂度O(nlog^2n); 代码: #in

树链剖分-模板题 HAOI2015

1 #include <stdio.h> 2 #include <vector> 3 4 using namespace std; 5 6 typedef long long LL; 7 8 const int _N = 1000000; 9 10 vector<LL> G[_N]; 11 LL Size[_N], ID[_N], Anc[_N], Hson[_N], D[_N], Dad[_N], A[_N]; 12 LL Seg_root, Seg_cnt, L[_

bzoj 4034: [HAOI2015]T2

树刨 一定要注意long long 1 #include<cstdio> 2 #include<iostream> 3 #include<cstring> 4 #include<cstdlib> 5 #include<cmath> 6 #include<queue> 7 #include<algorithm> 8 #include<vector> 9 #define M 2000009 10 #define E

数据结构(树链剖分):COGS 2109. [NOIP2015] 运输计划

2109. [NOIP2015] 运输计划 ★★★   输入文件:transport.in   输出文件:transport.out   简单对比时间限制:1 s   内存限制:256 MB [题目描述] 公元 2044 年,人类进入了宇宙纪元. L 国有 n 个星球,还有 n-1 条双向航道,每条航道建立在两个星球之间,这 n-1 条航道连通了 L 国的所有星球. 小 P 掌管一家物流公司,该公司有很多个运输计划,每个运输计划形如:有一艘物 流飞船需要从 ui 号星球沿最快的宇航路径飞行到 v

数据结构(树链剖分,堆):HNOI 2016 network

2215. [HNOI2016]网络 ★★★☆   输入文件:network_tenderRun.in   输出文件:network_tenderRun.out   简单对比时间限制:2 s   内存限制:128 MB [题目描述] [输入格式] [输出格式] [样例输入1] 13 23 1 2 1 3 2 4 2 5 3 6 3 7 4 8 4 9 6 10 6 11 7 12 7 13 2 1 0 8 13 3 0 9 12 5 2 9 2 8 2 2 0 10 12 1 2 2 1 3 2

浅析树链剖分Orz

本文思路参考自何开大佬 引子 相信各位大佬一定会线段树这种非常实用的数据结构 那么如果我们要维护一棵树上的链的权值的时候怎么办 就比如说BZOJ1036树的统计这道题目 可能诸位草率地想想线段树是可以口头AC的,But 这是在一棵树上,线段树支持的连续的区间操作 在这棵树上,如果链的编号断断续续,那么我们的线段树就和暴力没有什么区别有一点点区别了 概念 所以这里就需要用到树链剖分,这种可以支持树上链操作的数据结构 树链剖分有很多高大上的名词需要我们去记 我们先定义一些概念东东 size[u]表示

bzoj 4034: [HAOI2015]树上操作 树链剖分+线段树

4034: [HAOI2015]树上操作 Time Limit: 10 Sec  Memory Limit: 256 MBSubmit: 4352  Solved: 1387[Submit][Status][Discuss] Description 有一棵点数为 N 的树,以点 1 为根,且树点有边权.然后有 M 个 操作,分为三种: 操作 1 :把某个节点 x 的点权增加 a . 操作 2 :把某个节点 x 为根的子树中所有点的点权都增加 a . 操作 3 :询问某个节点 x 到根的路径中所有