HDU 5044 TREE

题意:一棵树上两种操作,操作1,改变u到v的每一点的值增加k,操作2,改变u到v每一条边值增加k。最后结束时问,每一点和每一条边的值。

初始时,点和边的值都为0.

分析:

很显然要用树链剖分,将点和边分别划分成连续一段的编号,然后就是维护一段一段的值了,给它增加一个值,由于题目只需要输出最后结果,那么可以用树桩数组维护。

以边为例,对于l~r的每个值增加k,利用树桩数组v[i]表示第i个值与前一个值的差值,那么第k条边的值就是sum{v[i]| 1 <= i <= k},更新时则只要给v[l]加k,给v[r+1]加(- k), 这个都可以累加下来,最后依次对每个v[i]更新,然后求出结果就行了。

代码:

  1 #include <iostream>
  2 #include <algorithm>
  3 #include <vector>
  4 #include <map>
  5 #include <cstring>
  6 #include <set>
  7 #include <bitset>
  8 #include <cstdio>
  9 #include <cmath>
 10 #define esp 1e-8
 11 #pragma comment(linker, "/STACK:102400000,102400000")
 12 #define in freopen("F:\\rootial\\data\\data.txt", "r", stdin);
 13 #define IN freopen("solve_in.txt", "r", stdin);
 14 #define out freopen("out.txt", "w", stdout);
 15 #define pf(x) ((x)*(x))
 16 #define lowbit(x) ((x)&(-(x)))
 17 #define bug(x) printf("Line %d: >>>>>>\n", (x));
 18 #define lson l, m, rt<<1
 19 #define rson m+1, r, rt<<1|1
 20 #define pb push_back
 21 #define mp make_pair
 22 #define pi acos(-1.0)
 23 #define pf(x) ((x)*(x))
 24
 25 using namespace std;
 26 typedef long long LL;
 27 typedef pair<int, int> PII;
 28 typedef map<LL,  LL> MPS;
 29 typedef MPS::iterator IT;
 30
 31 const int maxn = (int)1e5 + 100;
 32 LL vv[2][maxn];
 33 int n, m;
 34 int top[maxn], num[maxn], tnum[maxn], ID[maxn], son[maxn], sz[maxn], fa[maxn], dep[maxn], tmp[maxn];
 35 int cnt;
 36
 37 struct Edge
 38 {
 39     int v, id;
 40     Edge() {}
 41     Edge(int v, int id):v(v), id(id) {}
 42 } edge[maxn*2];
 43 int fi[maxn], nxt[maxn*2];
 44 LL q[2][maxn];
 45
 46 void update(int x, LL v[], LL val)
 47 {
 48     while(x <= n)
 49     {
 50         v[x] +=val;
 51         x += lowbit(x);
 52     }
 53 }
 54 void update(int l, int r, LL val, LL v[])
 55 {
 56     update(l, v, val);
 57     update(r+1, v, -val);
 58 }
 59
 60 void query(int x, LL &res1, LL &res2)
 61 {
 62     res1 = 0, res2 = 0;
 63     while(x > 0)
 64     {
 65         res1 += vv[0][x];
 66         res2 += vv[1][x];
 67         x -= lowbit(x);
 68     }
 69 }
 70 void dfs1(int u, int f)
 71 {
 72     fa[u] = f;
 73     dep[u] = dep[f] + 1;
 74     sz[u] = 1;
 75     for(int i = fi[u]; i; i = nxt[i])
 76     {
 77         int v = edge[i].v;
 78         int id = edge[i].id;
 79         if(v == f)
 80             continue;
 81         tmp[v] = id;
 82         dfs1(v, u);
 83         sz[u] += sz[v];
 84         if(sz[son[u]] < sz[v])
 85             son[u] = v;
 86     }
 87 }
 88 void dfs2(int u, int f)
 89 {
 90     if(son[u])
 91     {
 92         num[son[u]] = ++cnt;
 93         top[son[u]] = top[u];
 94         ID[tmp[son[u]]] = cnt;
 95         dfs2(son[u], u);
 96     }
 97     for(int i = fi[u]; i; i = nxt[i])
 98     {
 99         int v = edge[i].v;
100         int id = edge[i].id;
101         if(v == f || v == son[u]) continue;
102         top[v] = v;
103         num[v] = ++cnt;
104         ID[tmp[v]] = cnt;
105         dfs2(v, u);
106     }
107 }
108 void init()
109 {
110     for(int i = 0; i <= n; i++)
111     {
112         vv[0][i] = vv[1][i] = 0;
113         son[i] = 0;
114         sz[i] = 0;
115         fa[i] = 0;
116         cnt = 0;
117         fi[i] = 0;
118         nxt[i<<1] = nxt[i<<1|1] = 0;
119         q[0][i] = q[1][i] = 0;
120     }
121 }
122 void add(int u, int v, int x)
123 {
124     edge[++cnt] = Edge(v, x);
125     nxt[cnt] = fi[u];
126     fi[u] = cnt;
127     edge[++cnt] = Edge(u, x);
128     nxt[cnt] = fi[v];
129     fi[v] = cnt;
130 }
131 void input()
132 {
133     scanf("%d%d", &n, &m);
134     init();
135     for(int i = 1; i < n; i++)
136     {
137         int u, v;
138         scanf("%d%d", &u, &v);
139         add(u, v, i);
140     }
141     cnt = 0;
142 }
143 inline bool isdigit(char ch)
144 {
145     return ch >= ‘0‘ && ch <= ‘9‘;
146 }
147 const LL B = (int)1e5 + 10;
148
149 void update(int u, int v, int k) //dian
150 {
151     while(top[u] != top[v])
152     {
153         if(dep[top[u]] < dep[top[v]]) swap(u, v);
154         q[0][num[top[u]]] += k;
155         q[0][num[u]+1] -= k;
156         u = fa[top[u]];
157     }
158     if(dep[u] < dep[v]) swap(u, v);
159     q[0][num[v]] += k;
160     q[0][num[u]+1] -= k;
161 }
162 void update1(int u, int v, int k) //bian
163 {
164     while(top[u] != top[v])
165     {
166         if(dep[top[u]] < dep[top[v]]) swap(u, v);
167         if(u != top[u])
168         {
169             q[1][num[son[top[u]]]] += k;
170             q[1][num[u]+1] -= k;
171         }
172         u = top[u];
173         q[1][num[u]] += k;
174         q[1][num[u]+1] -= k;;
175         u = fa[u];
176     }
177     if(dep[u] < dep[v]) swap(u, v);
178     if(u != v)
179     {
180         q[1][num[son[v]]] += k;
181         q[1][num[u]+1] -=  k;
182     }
183 }
184 LL ans[maxn];
185
186 void solve()
187 {
188     dfs1(1, 0);
189     top[1] = 1;
190     num[1] = ++cnt;
191     dfs2(1, 0);
192     for(int i = 0; i < m; i++)
193     {
194         char s[20];
195         int u, v, k;
196         scanf("%s%d%d%d", s, &u, &v, &k);
197         if(strcmp(s, "ADD1") == 0)
198         {
199             update(u, v, k);
200         }
201         else
202         {
203             update1(u, v, k);
204         }
205     }
206     for(int k = 0; k < 2; k++){
207             for(int i = 1; i <= n; i++)
208                 update(i, vv[k], q[k][i]);
209         }
210
211     for(int i = 1; i <= n; i++)
212     {
213         LL res1, res2;
214         query(num[i], res1, res2);
215         ans[num[i]] = res2;
216         printf("%I64d%c", res1, i == n ? ‘\n‘ : ‘ ‘);
217     }
218     for(int i = 1; i <= n-1; i++)
219     {
220         LL res = ans[ID[i]];
221         printf("%I64d%c", res, i == n-1 ? ‘\n‘ : ‘ ‘);
222     }
223     if(n == 1)
224         puts("");
225 }
226 int main()
227 {
228
229     int T;
230     for(int t = scanf("%d", &T); t <= T; t++)
231     {
232         printf("Case #%d:\n", t);
233         input();
234         solve();
235     }
236     return 0;
237 }

时间: 2024-10-25 13:31:06

HDU 5044 TREE的相关文章

HDU 5044 Tree(树链剖分)

HDU 5044 Tree 题目链接 就简单的树链剖分,不过坑要加输入外挂,还要手动扩栈 代码: #include <cstdio> #include <cstring> #include <vector> #include <algorithm> using namespace std; const int N = 100005; #pragma comment(linker, "/STACK:1024000000,1024000000"

树链剖分 [HDU 5044] Tree

Tree Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Total Submission(s): 2038    Accepted Submission(s): 391 Problem Description You are given a tree (an acyclic undirected connected graph) with N nodes. The tree

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 5293 Tree chain problem(树链剖分+树形dp)

题目链接:hdu 5293 Tree chain problem 维护dp[u], sum[u],dp[u]表示以u为根节点的子树的最优值.sum[u]表示以u节点的所有子节点的dp[v]之和.对于边a,b,w,在LCA(a,b)节点的时候进行考虑.dp[u] = min{dp[u], Sum(a,b) - Dp(a,b) + sum[u] | (ab链上的点,不包括u } #pragma comment(linker, "/STACK:1024000000,1024000000")

hdu 5370 Tree Maker(catalan+dp)

题目链接:hdu 5370 Tree Maker n个节点的二叉树种类为Catalan数的第n项 对于一棵子树而言,被移动过的节点就是确定的位置,所以只要知道已经确定位置的K个节点有多少个空孩子指针M,和就该子树下的N个未确定位置的节点,等于是说用N个节点构造M个可为空的子树的种类数.对于整个树的形态数即为若干棵独立的子树形态数的乘积. 定义dp[i][j]为用i个节点构造j棵树的形态数,dp[i][j] = sum{ dp[i-1][j-k] * catalan[k] | 0 ≤ k ≤j }

hdu 4757 Tree(可持久化字典树)

题目链接:hdu 4757 Tree 题目大意:给定一棵树,每一个节点有一个值.如今有Q次询问,每次询问u到v路径上节点值与w亦或值的最大值. 解题思路:刚開始以为是树链剖分,事实上树链剖分仅仅是用来求LCA(能够不用树链剖分). 可持久化字典树.在每次插入的同一时候,不改动原先的节点.而是对全部改动的节点复制一个新的节点,而且在新的节点 上做操作,这样做的目的是可以获取某次改动前的状态.同过可持久化的操作,保留了改动前后的公共数据. 对给定树上的全部节点权值建立01字典树,然后每一个节点都保存

hdu 3534 Tree(树形DP)

题目链接:hdu 3534 Tree 题意: 给你一棵n个节点,n-1条边的树,每条边有一个长度,现在问你最长的边的长度为多少,有多少条. 题解: 其实这种题不用记录最长和次长,我们开两个数组,len[i],num[i]. 表示以i为根结点出发的最长的长度以及最长的边的条数. 然后我们只需要一个dfs,先用子节点的信息来更新答案,然后在更新当前节点的len和num记录的信息. 这样就不用记录最长和次长. 1 #include<bits/stdc++.h> 2 #define mst(a,b)

HDU 1710-Binary Tree Traversals(重建二叉树)

Binary Tree Traversals Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 3340    Accepted Submission(s): 1500 Problem Description A binary tree is a finite set of vertices that is either empty or

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

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