题目大意:
  给你一棵n个点的树,以1为根,每个点都有一个点权,要求进行如下操作:
  1.将x这个点的点权加上a;
  2.将以x这个点为根的子树中每个点的点权加上a;
  3.查询从x到根的路径的点权和。

思路:
  树链剖分。
  对于第2种操作,我们不难发现一个子树中结点在线段树中的编号一定是连续的。
  于是修改子树的操作就是线段树上修改id[x]~id[x]+size[x]-1的操作。

  1 #include<cstdio>
  2 #include<cctype>
  3 #include<vector>
  4 typedef long long int64;
  5 inline int getint() {
  6     register char ch;
  7     register bool neg=false;
  8     while(!isdigit(ch=getchar())) if(ch=='-') neg=true;
  9     register int x=ch^'0';
 10     while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0');
 11     return neg?-x:x;
 12 }
 13 const int N=100001;
 14 std::vector<int> e[N];
 15 inline void add_edge(const int &u,const int &v) {
 16     e[u].push_back(v);
 17     e[v].push_back(u);
 18 }
 19 int n,size[N],par[N],dep[N],id[N],son[N],top[N],w[N],node[N];
 20 void dfs1(const int &x,const int &par) {
 21     ::par[x]=par;
 22     dep[x]=dep[par]+1;
 23     size[x]=1;
 24     for(unsigned i=0;i<e[x].size();i++) {
 25         const int &y=e[x][i];
 26         if(y==par) continue;
 27         dfs1(y,x);
 28         size[x]+=size[y];
 29         if(size[y]>size[son[x]]) son[x]=y;
 30     }
 31 }
 32 void dfs2(const int &x) {
 33     id[x]=++id[0];
 34     node[id[x]]=x;
 35     if(x==son[par[x]]) {
 36         top[x]=top[par[x]];
 37     } else {
 38         top[x]=x;
 39     }
 40     if(son[x]) dfs2(son[x]);
 41     for(unsigned i=0;i<e[x].size();i++) {
 42         const int &y=e[x][i];
 43         if(y==par[x]||y==son[x]) continue;
 44         dfs2(y);
 45     }
 46 }
 47 class SegmentTree {
 48     #define _left <<1
 49     #define _right <<1|1
 50     private:
 51         int64 val[N<<2],tag[N<<2];
 52         void push_up(const int &p) {
 53             val[p]=val[p _left]+val[p _right];
 54         }
 55         int size(const int &b,const int &e) const {
 56             return e-b+1;
 57         }
 58         void push_down(const int &p,const int &b,const int &e) {
 59             const int mid=(b+e)>>1;
 60             val[p _left]+=tag[p]*size(b,mid);
 61             val[p _right]+=tag[p]*size(mid+1,e);
 62             tag[p _left]+=tag[p];
 63             tag[p _right]+=tag[p];
 64             tag[p]=0;
 65         }
 66     public:
 67         void build(const int &p,const int &b,const int &e) {
 68             if(b==e) {
 69                 val[p]=w[node[b]];
 70                 return;
 71             }
 72             const int mid=(b+e)>>1;
 73             build(p _left,b,mid);
 74             build(p _right,mid+1,e);
 75             push_up(p);
 76         }
 77         void modify(const int &p,const int &b,const int &e,const int &l,const int &r,const int &x) {
 78             if(b==l&&e==r) {
 79                 val[p]+=(int64)x*size(b,e);
 80                 tag[p]+=x;
 81                 return;
 82             }
 83             const int mid=(b+e)>>1;
 84             push_down(p,b,e);
 85             if(l<=mid) modify(p _left,b,mid,l,std::min(mid,r),x);
 86             if(r>mid) modify(p _right,mid+1,e,std::max(mid+1,l),r,x);
 87             push_up(p);
 88         }
 89         int64 query(const int &p,const int &b,const int &e,const int &l,const int &r) {
 90             if(b==l&&e==r) {
 91                 return val[p];
 92             }
 93             const int mid=(b+e)>>1;
 94             push_down(p,b,e);
 95             int64 ret=0;
 96             if(l<=mid) ret+=query(p _left,b,mid,l,std::min(mid,r));
 97             if(r>mid) ret+=query(p _right,mid+1,e,std::max(mid+1,l),r);
 98             return ret;
 99         }
100     #undef _left
101     #undef _right
102 };
103 SegmentTree t;
104 inline int64 query(int x) {
105     int64 ret=0;
106     while(x) {
107         ret+=t.query(1,1,n,id[top[x]],id[x]);
108         x=par[top[x]];
109     }
110     return ret;
111 }
112 int main() {
113     n=getint();
114     const int m=getint();
115     for(register int i=1;i<=n;i++) {
116         w[i]=getint();
117     }
118     for(register int i=1;i<n;i++) {
119         add_edge(getint(),getint());
120     }
121     dfs1(1,0);
122     dfs2(1);
123     t.build(1,1,n);
124     for(register int i=0;i<m;i++) {
125         const int op=getint(),x=getint();
126         if(op==1) {
127             t.modify(1,1,n,id[x],id[x],getint());
128         }
129         if(op==2) {
130             t.modify(1,1,n,id[x],id[x]+size[x]-1,getint());
131         }
132         if(op==3) {
133             printf("%lld\n",query(x));
134         }
135     }
136     return 0;
137 }

View Code

  题目求的是点到根路径上的权值和,那么修改单点对整棵子树所有结点的询问都有贡献。
  给整棵子树增加权值显然也会对整棵子树的询问产生贡献。
  若v是u的子树中的一个点,对结点u为根的子树的每一个结点权值增加a,相当于给针对v的询问答案增加了(dis(u,v)+1)a。
  考虑将树“压扁”,求出树的DFS序。 对于结点u的子树,DFS序范围是dfn[u]~dfn[u]+size[u]-1。
  用线段树维护两个值x和y,分别代表需要乘dis的权值和不需要乘dis的权值,询问时返回dep[u]*x[u]+y[u]即可。

 1 #include<cstdio>
 2 #include<cctype>
 3 #include<vector>
 4 typedef long long int64;
 5 inline int getint() {
 6     register char ch;
 7     register bool neg=false;
 8     while(!isdigit(ch=getchar())) if(ch=='-') neg=true;
 9     register int x=ch^'0';
10     while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0');
11     return neg?-x:x;
12 }
13 const int N=100001;
14 int w[N],dfn[N],size[N],dep[N];
15 std::vector<int> e[N];
16 inline void add_edge(const int &u,const int &v) {
17     e[u].push_back(v);
18     e[v].push_back(u);
19 }
20 void dfs(const int &x,const int &par) {
21     size[x]=1;
22     dfn[x]=++dfn[0];
23     dep[x]=dep[par]+1;
24     for(unsigned i=0;i<e[x].size();i++) {
25         const int &y=e[x][i];
26         if(y==par) continue;
27         dfs(y,x);
28         size[x]+=size[y];
29     }
30 }
31 class SegmentTree {
32     #define _left <<1
33     #define _right <<1|1
34     private:
35         int64 val1[N<<2],val2[N<<2];
36     public:
37         void modify(const int &p,const int &b,const int &e,const int &l,const int &r,const int &x,const int64 &y) {
38             if(b==l&&e==r) {
39                 val1[p]+=x;
40                 val2[p]+=y;
41                 return;
42             }
43             const int mid=(b+e)>>1;
44             if(l<=mid) modify(p _left,b,mid,l,std::min(mid,r),x,y);
45             if(r>mid) modify(p _right,mid+1,e,std::max(mid+1,l),r,x,y);
46         }
47         int64 query(const int &p,const int &b,const int &e,const int &x) {
48             int64 ret=val1[p]*dep[x]+val2[p];
49             if(b==e) return ret;
50             const int mid=(b+e)>>1;
51             if(dfn[x]<=mid) ret+=query(p _left,b,mid,x);
52             if(dfn[x]>mid) ret+=query(p _right,mid+1,e,x);
53             return ret;
54         }
55     #undef _left
56     #undef _right
57 };
58 SegmentTree t;
59 int main() {
60     const int n=getint(),m=getint();
61     for(register int i=1;i<=n;i++) {
62         w[i]=getint();
63     }
64     for(register int i=1;i<n;i++) {
65         add_edge(getint(),getint());
66     }
67     dfs(1,0);
68     for(register int i=1;i<=n;i++) {
69         t.modify(1,1,n,dfn[i],dfn[i]+size[i]-1,0,w[i]);
70     }
71     for(register int i=0;i<m;i++) {
72         const int op=getint();
73         if(op==1) {
74             const int x=getint(),a=getint();
75             t.modify(1,1,n,dfn[x],dfn[x]+size[x]-1,0,a);
76         }
77         if(op==2) {
78             const int x=getint(),a=getint();
79             t.modify(1,1,n,dfn[x],dfn[x]+size[x]-1,a,a-(int64)dep[x]*a);
80         }
81         if(op==3) {
82             const int x=getint();
83             printf("%lld\n",t.query(1,1,n,x));
84         }
85     }
86     return 0;
87 }

View Code

  同样还是一种将树“压扁”的方法。
  考虑我们之前讲过的括号序列。
  操作3中的询问相当于前缀和。 
  按照括号序列建线段树,操作1就变成了单点修改,操作2就变成了区间+a/-a。

 1 #include<cstdio>
 2 #include<cctype>
 3 #include<vector>
 4 typedef long long int64;
 5 inline int getint() {
 6     register char ch;
 7     register bool neg=false;
 8     while(!isdigit(ch=getchar())) if(ch=='-') neg=true;
 9     register int x=ch^'0';
10     while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0');
11     return neg?-x:x;
12 }
13 const int N=100001;
14 int w[N],dfn[N],size[N],dep[N];
15 std::vector<int> e[N];
16 inline void add_edge(const int &u,const int &v) {
17     e[u].push_back(v);
18     e[v].push_back(u);
19 }
20 void dfs(const int &x,const int &par) {
21     size[x]=1;
22     dfn[x]=++dfn[0];
23     dep[x]=dep[par]+1;
24     for(unsigned i=0;i<e[x].size();i++) {
25         const int &y=e[x][i];
26         if(y==par) continue;
27         dfs(y,x);
28         size[x]+=size[y];
29     }
30 }
31 class SegmentTree {
32     #define _left <<1
33     #define _right <<1|1
34     private:
35         int64 val1[N<<2],val2[N<<2];
36     public:
37         void modify(const int &p,const int &b,const int &e,const int &l,const int &r,const int &x,const int64 &y) {
38             if(b==l&&e==r) {
39                 val1[p]+=x;
40                 val2[p]+=y;
41                 return;
42             }
43             const int mid=(b+e)>>1;
44             if(l<=mid) modify(p _left,b,mid,l,std::min(mid,r),x,y);
45             if(r>mid) modify(p _right,mid+1,e,std::max(mid+1,l),r,x,y);
46         }
47         int64 query(const int &p,const int &b,const int &e,const int &x) {
48             int64 ret=val1[p]*dep[x]+val2[p];
49             if(b==e) return ret;
50             const int mid=(b+e)>>1;
51             if(dfn[x]<=mid) ret+=query(p _left,b,mid,x);
52             if(dfn[x]>mid) ret+=query(p _right,mid+1,e,x);
53             return ret;
54         }
55     #undef _left
56     #undef _right
57 };
58 SegmentTree t;
59 int main() {
60     //freopen("221/haoi2015_t21.in","r+",stdin);
61     const int n=getint(),m=getint();
62     for(register int i=1;i<=n;i++) {
63         w[i]=getint();
64     }
65     for(register int i=1;i<n;i++) {
66         add_edge(getint(),getint());
67     }
68     dfs(1,0);
69     for(register int i=1;i<=n;i++) {
70         t.modify(1,1,n,dfn[i],dfn[i]+size[i]-1,0,w[i]);
71     }
72     for(register int i=0;i<m;i++) {
73         const int op=getint();
74         if(op==1) {
75             const int x=getint(),a=getint();
76             t.modify(1,1,n,dfn[x],dfn[x]+size[x]-1,0,a);
77         }
78         if(op==2) {
79             const int x=getint(),a=getint();
80             t.modify(1,1,n,dfn[x],dfn[x]+size[x]-1,a,a-(int64)dep[x]*a);
81         }
82         if(op==3) {
83             const int x=getint();
84             printf("%lld\n",t.query(1,1,n,x));
85         }
86     }
87     return 0;
88 }

View Code

转载于:https://www.cnblogs.com/skylee03/p/8066974.html

[HAOI2015]树上操作相关推荐

  1. P3178 [HAOI2015]树上操作

    P3178 [HAOI2015]树上操作 题意: 题解: 这已经是很裸的树链剖分了... 直接套模板 代码: #include<cmath> #include<cstdio> ...

  2. BZOJ 4043 [HAOI2015]树上操作 dfs序 线段树

    $ \Rightarrow $ 戳我进BZOJ原题 $ \Rightarrow $ 戳我进洛谷原题 [HAOI2015]树上操作 Time Limit: 10 Sec Memory Limit: 25 ...

  3. bzoj 4034: [HAOI2015]树上操作(树链剖分+线段树区间更新)

    4034: [HAOI2015]树上操作 Time Limit: 10 Sec  Memory Limit: 256 MB Submit: 4981  Solved: 1603 [Submit][St ...

  4. bzoj4034: [HAOI2015]树上操作

    这题其实就是树剖裸题啊. 然后毒瘤选手由于上题树剖被卡到哭所以选择dfs序+树状数组. 不得不说简单的算法做出来更加难思考.然后网上的dalao们都一笔带过净说什么用两个树状数组维护就可以啦. 经过大 ...

  5. [BZOJ 4034][HAOI2015]树上操作(欧拉序列+线段树)

    Description 有一棵点数为 N 的树,以点 1 为根,且树点有边权.然后有 M 个 操作,分为三种: 操作 1 :把某个节点 x 的点权增加 a . 操作 2 :把某个节点 x 为根的子树中 ...

  6. luogu P3178 [HAOI2015]树上操作

    题目 题目描述 有一棵点数为 N 的树,以点 1 为根,且树点有边权.然后有 M 个操作,分为三种: 操作 1 :把某个节点 x 的点权增加 a . 操作 2 :把某个节点 x 为根的子树中所有点的点 ...

  7. 省选专练HAOI2015树上操作

    题如其名 树链剖分板子题 #include<bits/stdc++.h> using namespace std; #define lc (p<<1) #define rc ( ...

  8. [BZOJ4033][HAOI2015]树上染色

    4033: [HAOI2015]树上染色 Time Limit: 10 Sec  Memory Limit: 256 MB Submit: 2108  Solved: 901 [Submit][Sta ...

  9. Luogu P3177 [HAOI2015] 树上染色(树上背包)

    整理的算法模板合集: ACM模板 点我看算法全家桶系列!!! 实际上是一个全新的精炼模板整合计划 Luogu P3177 [HAOI2015] 树上染色 有一棵点数为 NNN 的树,树边有边权.给你一 ...

最新文章

  1. 根据函数指针地址获取函数名
  2. 实验:交换机生成树协议STP--功能验证
  3. QUIC助力Snapchat提升用户体验
  4. Outlook 阅读窗格(Reading Pane)
  5. LeetCode OJ:Combination Sum III(组合之和III)
  6. matlab将矩阵分解成lu,MATLAB中矩阵LU分解
  7. 《概率论》大学课堂笔记——高分笔记,考试复习专用
  8. IC卡和ID卡的区别
  9. Occupancy Flow: 4D Reconstruction by Learning Particle Dynamics(1)
  10. 1. Win 10 :在此处打开命令窗口
  11. 使用计算机时注意的,使用计算机时注意几点预防“鼠标手”
  12. memory_max_target/memory_target设置过大报ORA-00845错误
  13. u盘打不开提示格式化怎么办?u盘恢复这样做
  14. 华清远见-创客学院-专业:嵌入式人工智能开发 C++ 课程(包含天猫精灵)
  15. 明星直播的品牌效应,这几个关键数据你一定要知道!
  16. 苹果电脑适合学python吗_千万别花冤枉钱!大学生买本得这么选!
  17. 足不出户怎么在家赚钱,暑假在家别闲着,给自己赚点生活费吧
  18. mysql不同版本乱码_技术|解决MySQL中文乱码以及版本不一致问题
  19. 回归分析中R方和调整R方的区别
  20. SpringBoot接收前端传来的json数据

热门文章

  1. boost::current_exception_cast的用法测试程序
  2. gdcm::ImageChangePhotometricInterpretation的测试程序
  3. DCMTK:使用RLE传输语法压缩DICOM文件
  4. VTK:可视化算法之TensorEllipsoids
  5. VTK:可视化算法之HeadSlice
  6. VTK:网格之ElevationFilter
  7. VTK:图片之ImageMedian3D
  8. VTK:图片之ExtractComponents
  9. 具有OpenCV和相似度测量的视频输入
  10. Qt Creator运行自动测试