HDU 3966 基础树链剖分

题意:给一棵树,并给定各个点权的值,然后有3种操作:
I C1 C2 K: 把C1与C2的路径上的所有点权值加上K
D C1 C2 K:把C1与C2的路径上的所有点权值减去K
Q C:查询节点编号为C的权值

  1 #pragma comment(linker, "/STACK:1024000000,1024000000")
  2 #include <iostream>
  3 #include <cstdio>
  4 #include <cstring>
  5 #include <algorithm>
  6 using namespace std;
  7 #define N 50010
  8 #define ls o<<1
  9 #define rs o<<1|1
 10 #define define_m int m=(l+r)>>1
 11 #define ll long long
 12 int n , m , q , first[N] , k;
 13
 14 struct Edge{
 15     int y , next;
 16     Edge(){}
 17     Edge(int y , int next):y(y),next(next){}
 18 }e[N<<1];
 19
 20 void add_edge(int x , int y)
 21 {
 22     e[k] = Edge(y , first[x]);
 23     first[x] = k++;
 24 }
 25
 26 int sz[N] , fa[N] , son[N] , top[N] , dep[N] , id[N] , number;
 27 void dfs(int u , int f , int d)
 28 {
 29     fa[u] = f;
 30     sz[u] = 1 , dep[u] = d , son[u] =0;
 31     int maxn = 0;
 32     for(int i=first[u] ; ~i ; i=e[i].next){
 33         int v= e[i].y;
 34         if(v == f) continue;
 35         dfs(v , u , d+1);
 36         sz[u] += sz[v];
 37         if(sz[v]>maxn) son[u] = v , maxn=sz[v];
 38     }
 39 }
 40
 41 void dfs1(int u , int f , int head)
 42 {
 43     top[u] = head;
 44     if(son[u]){
 45         id[son[u]] = ++number;
 46         dfs1(son[u] , u , head);
 47     }
 48     for(int i=first[u] ; ~i ; i=e[i].next){
 49         int v = e[i].y;
 50         if(v == f || v == son[u]) continue;
 51         id[v] = ++number;
 52         dfs1(v , u , v);
 53     }
 54 }
 55
 56 int val[N] , add[N<<2] , siz[N<<2];
 57 ll sum[N<<2];
 58
 59 void push_up(int o){sum[o] = sum[ls]+sum[rs];}
 60
 61 void push_down(int o)
 62 {
 63     if(add[o]){
 64         add[ls] += add[o] , add[rs] += add[o];
 65         sum[ls] += (ll)add[o]*siz[ls] , sum[rs] += (ll)add[o]*siz[rs];
 66         add[o] = 0;
 67     }
 68 }
 69
 70 void build(int o , int l , int r)
 71 {
 72     add[o] = 0 , siz[o] = r-l+1;
 73     if(l==r){
 74         sum[o] = (ll)val[l];
 75         return ;
 76     }
 77     define_m;
 78     build(ls , l , m);
 79     build(rs , m+1 , r);
 80     push_up(o);
 81 }
 82
 83 void update(int o , int l , int r , int s , int t , int v)
 84 {
 85     if(l>=s && r<=t){
 86         sum[o] += (ll)siz[o]*v;
 87         add[o] += v;
 88         return ;
 89     }
 90     define_m;
 91     push_down(o);
 92     if(m>=s) update(ls , l , m , s , t , v);
 93     if(m<t) update(rs , m+1 , r , s , t , v);
 94     push_up(o);
 95 }
 96
 97 ll query(int o , int l , int r , int p)
 98 {
 99     if(l==r && l==p) return sum[o];
100     push_down(o);
101     define_m;
102     if(m>=p) return query(ls , l , m, p);
103     else return query(rs , m+1 , r , p);
104 }
105
106 void updatePath(int u , int v , int change)
107 {
108     int top1 = top[u] , top2 = top[v];
109     while(top1!=top2){
110         if(dep[top1]<dep[top2]){
111             swap(top1 , top2);
112             swap(u , v);
113         }
114         update(1 , 1 , n , id[top1] , id[u] , change);
115         u = fa[top1];
116         top1 = top[u];
117     }
118
119     if(dep[u]<dep[v]) swap(u , v);
120     update(1 , 1 , n , id[v] , id[u] , change);
121
122 }
123
124 char str[4];
125
126 int main()
127 {
128    // freopen("in.txt" , "r" , stdin);
129     while(~scanf("%d%d%d" ,&n , &m , &q))
130     {
131         for(int i=1 ; i<=n ; i++) scanf("%d" , val+i);
132         memset(first , -1 , sizeof(first));
133         k = 0;
134         while(m--){
135             int u , v;
136             scanf("%d%d" , &u , &v);
137             add_edge(u,v);
138             add_edge(v,u);
139         }
140         number = 0;
141         dfs(1 , 0 , 1);
142         id[1] = ++number;
143         dfs1(1 , 0 , 1);
144       //  for(int i=1 ; i<=n ; i++) cout<<i<<" "<<son[i]<<" "<<id[i]<<endl;
145         int tmp[N];
146         for(int i=1 ; i<=n ; i++) tmp[i]=val[i];
147         for(int i=1 ; i<=n ; i++) val[id[i]] = tmp[i];
148         build(1 , 1 , n);
149         for(int i=0 ; i<q ; i++){
150             int s , t , v;
151             scanf("%s" , str);
152             if(str[0] == ‘Q‘){
153                 scanf("%d" , &v);
154                 ll ans = query(1 , 1 , n , id[v]);
155                 printf("%d\n" , (int)ans);
156             }else if(str[0]==‘I‘){
157                 scanf("%d%d%d" , &s , &t , &v);
158                 updatePath(s , t , v);
159             }else{
160                 scanf("%d%d%d" , &s , &t , &v);
161                 updatePath(s , t , -v);
162             }
163         }
164     }
165     return 0;
166 }
时间: 2024-08-27 21:13:18

HDU 3966 基础树链剖分的相关文章

HDU 3966 RE 树链剖分 Aragorn&#39;s Story

给一棵点带权的图 有这样一个操作: 使树上某一条路径所有点权值增减 每次询问某个点现在的权值. 树链剖分完以后,就是线段树的成段更新了. 这题感觉A不了了,无限RE,手动开栈也没卵用. 还是把我辛辛苦苦写的代码贴一下吧. 1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <algorithm> 5 #include <vector> 6 using

HDU 3966(树链剖分+点修改+点查询)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3966 题目大意:营地的分布成树型.每个营地都有一些人,每次修改修改一条链上的所有营地的人数,每次查询单个点. 解题思路: 树链剖分基础题. 维护一个sum. 注意轻链修改时,点修改和边修改的不同. 由于树的结构与线段树点的顺序不太相同,因此需要做一个映射数组rank.故在线段树Build的时候,权值是camp[rank[l]],rank这步的映射在dfs2的时候完成,rank[w[u]]=u; Qu

hdu 5458 Stability(树链剖分+并查集)

Stability Time Limit: 3000/2000 MS (Java/Others)    Memory Limit: 65535/102400 K (Java/Others)Total Submission(s): 1347    Accepted Submission(s): 319 Problem Description Given an undirected connected graph G with n nodes and m edges, with possibly r

HDU 5044 (树链剖分+树状数组+点/边改查)

题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=5044 题目大意:修改链上点,修改链上的边.查询所有点,查询所有边. 解题思路: 2014上海网赛的变态树链剖分模板题.将以往树链剖分的点&边修改和查询合在一起之后,难度上去不少. 第一个卡人点是读入优化. 第二个卡人点是树状数组.由于要查询所有点,如果使用线段树,每次都要扫到底层才能取出点值,必T无疑. 然后使用树状数组之后,树链剖分的点/边修改写法有些变动. 点查询变化不大. 边查询只要查询一下

HDU 5458 Stability (树链剖分+并查集+set)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5458 给你n个点,m条边,q个操作,操作1是删边,操作2是问u到v之间的割边有多少条. 这题要倒着做才容易,倒着加边. 因为这题最后保证所有的点一定连通,所以可以构建一棵树,树链剖分一下.要是u到v之间只有一条边,那便是一条割边.而加边的话,就是将u到v之间的边权都+1,边权等于1的话是桥,大于1的话就不是了.所以我们初始化树的时候,可以将边权初始化为1,加边操作将边权赋值为0.求u到v的割边个数的

HDU 5044 Tree 树链剖分

一棵树,初始边权和点权都为0 现在有m个操作,每一个操作: ADD1 u v k: for nodes on the path from u to v, the value of these nodes increase by k. ADD2 u v k: for edges on the path from u to v, the value of these edges increase by k. 操作完后,输出每一个点的点权和每一条边的边权(边权按照输入顺序输出) 我们把边权也当做点权处

HDU 5242 利用树链剖分思想进行贪心

题目大意: 在给定带权值节点的树上从1开始不回头走到某个底端点后得到所有经过的点的权值后,这些点权值修改为0,到达底部后重新回到1,继续走,问走k次,最多能得到多少权值之和 这其实就是相当于每一次都走权值最大的那一条路径,进行贪心k次 首先先来想想树链剖分的时候的思想: 重儿子表示这个儿子对应的子树的节点数最多,那么每次访问都优先访问重儿子 这道题里面我们进行一下转化,如果当前儿子能走出一条最长的路径,我们就令其为重儿子,那么很容易想到,到达父亲时,如果选择重儿子,那么之前到达 父亲所得的权值一

Hdu 3966 Aragorn&#39;s Story (树链剖分 + 线段树区间更新)

题目链接: Hdu 3966 Aragorn's Story 题目描述: 给出一个树,每个节点都有一个权值,有三种操作: 1:( I, i, j, x ) 从i到j的路径上经过的节点全部都加上x: 2:( D, i, j, x ) 从i到j的路径上经过的节点全部都减去x: 3:(Q, x) 查询节点x的权值为多少? 解题思路: 可以用树链剖分对节点进行hash,然后用线段树维护(修改,查询),数据范围比较大,要对线段树进行区间更新 1 #include <cstdio> 2 #include

HDU 2966 Aragorn&#39;s Story 树链剖分第一题 基础题

Problem Description Our protagonist is the handsome human prince Aragorn comes from The Lord of the Rings. One day Aragorn finds a lot of enemies who want to invade his kingdom. As Aragorn knows, the enemy has N camps out of his kingdom and M edges c