FZU2176---easy problem (树链剖分)

http://acm.fzu.edu.cn/problem.php?pid=2176

Problem 2176 easy problem

Accept: 9    Submit: 32
Time Limit: 2000 mSec    Memory Limit : 32768 KB

 Problem Description

给定一棵n个节点以1为根的树,初始每个节点的值为0,现在我们要在树上进行一些操作,操作有两种类型。

1 x val 表示对以x为根的子树的每个点进行加权操作(我们定义每个节点的深度为每个节点到根1的距离),如果 y是以x为根的子树中的点那么 y节点的权值增加 ((dep[y]-dep[x])%k+1)*val 其中dep[y]表示y节点的深度,k为一个常数(1<=k<=5)

2 x 查询当前x节点的权值。

 Input

首先输入一个整数T 表示数据的组数,每组数据 第一行有3个整数 n ,m, k(1<=n,m<=50000, 1<=k<=5) 。n表示节点数,m表示操作数,k表示如题目描述的常数。

接下去n-1行描述一棵树。接下去m行每行表示 一个操作 有两种类型1 x val 表示第一种类型 2 x 表示第二种类型。(1<=x<=n,1<=val<=100)

 Output

每组数据首先输出 Case#x: 表示第x组数据 x从1开始。接下去对于每组数据中的每个查询操作输出查询结果。(具体输出格式看样例)

 Sample Input

1

5 7 2

1 2

2 4

2 5

1 3

1 2 3

1 1 2

2 1

2 2

2 3

2 4

2 5

 Sample Output

Case#1:

2

7

4

8

8

大致思路:首先树链剖分一下,然后用树状数组或者线段树维护区间更新,但是((dep[y]-dep[x])%k+1)*val这种该怎么更新呢,,看到k很小最大只有5,可以想到用5棵线段树或者树状数组来维护。首先每个节点的深度dep确定后 每隔k个深度权值增加的是相等的。这样的话 就可以把所有的点对应到 k个树状数组 上去。然后就是树状数组经典的区间更新单点查询操作了。

  1 #include <set>
  2 #include <map>
  3 #include <cmath>
  4 #include <ctime>
  5 #include <queue>
  6 #include <stack>
  7 #include <cstdio>
  8 #include <string>
  9 #include <vector>
 10 #include <cstdlib>
 11 #include <cstring>
 12 #include <iostream>
 13 #include <algorithm>
 14 using namespace std;
 15 typedef unsigned long long ull;
 16 typedef long long ll;
 17 const int inf = 0x3f3f3f3f;
 18 const double eps = 1e-8;
 19 const int maxn = 5e4+10;
 20 struct
 21 {
 22     int to,next;
 23 } e[maxn<<1];
 24 int tot,head[maxn];
 25 void add_edge(int x,int y)
 26 {
 27     e[tot].to = y;
 28     e[tot].next = head[x];
 29     head[x] = tot++;
 30 }
 31 int siz[maxn],son[maxn],fa[maxn],dep[maxn];
 32 void dfs(int root)
 33 {
 34     siz[root] = 1;
 35     son[root] = 0;
 36     for (int i = head[root]; ~i; i = e[i].next)
 37     {
 38         if (fa[root] != e[i].to)
 39         {
 40             fa[e[i].to] = root;
 41             dep[e[i].to] = dep[root] + 1;
 42             dfs(e[i].to);
 43             if (siz[e[i].to] > siz[son[root]])
 44                 son[root] = e[i].to;
 45             siz[root] += siz[e[i].to];
 46         }
 47     }
 48 }
 49 int pos[maxn],top[maxn],L[maxn],R[maxn],bj1,bj2,idx;
 50 void build (int root,int father)
 51 {
 52     pos[root] = ++idx;
 53     top[root] = father;
 54     L[root] = root;
 55     R[root] = root;
 56     if (son[root] > 0)
 57     {
 58         bj1 = son[root];
 59         build(son[root],top[root]);
 60         L[root] = bj1;
 61     }
 62     bool flag = 0;
 63     for (int i = head[root]; ~i; i = e[i].next)
 64     {
 65         flag = 1;
 66         if (fa[root] != e[i].to && son[root] != e[i].to)
 67             bj2 = e[i].to,build(e[i].to,e[i].to);
 68         else if (siz[root] == 1)
 69             bj2 = root;
 70     }
 71     if (flag)
 72         R[root] = bj2;
 73 }
 74 int lowbit(int x)
 75 {
 76     return x & -x;
 77 }
 78 int c[6][maxn],n;
 79 void add(int x,int d,int k)
 80 {
 81     while (x <= n)
 82     {
 83         c[k][x] += d;
 84         x += lowbit(x);
 85     }
 86 }
 87 int sum(int x,int k)
 88 {
 89     int ans = 0;
 90     while (x > 0)
 91     {
 92         ans += c[k][x];
 93         x -= lowbit(x);
 94     }
 95     return ans;
 96 }
 97 void init()
 98 {
 99     int root = 1;
100     tot = idx = 0;
101     dep[root] = fa[root] = 0;
102     memset(head,-1,sizeof(head));
103     memset(siz,0,sizeof(siz));
104     memset(c,0,sizeof(c));
105     for (int i = 1; i < n; i++)
106     {
107         int u,v;
108         scanf ("%d%d",&u,&v);
109         add_edge(u,v);
110         add_edge(v,u);
111     }
112     dfs(root);
113     build(root,root);
114 }
115 int main(void)
116 {
117 #ifndef ONLINE_JUDGE
118     freopen("in.txt","r",stdin);
119 #endif
120     int t,cas = 1;
121     scanf ("%d",&t);
122     while (t--)
123     {
124         printf("Case#%d:\n",cas++);
125         int k,m;
126         scanf ("%d%d%d",&n,&m,&k);
127         init();
128         for (int i = 0; i < m; i++)
129         {
130             int op,x,val;
131             scanf ("%d%d",&op,&x);
132             if (op == 1)
133             {
134                 scanf ("%d",&val);
135                 for (int j = 0; j < k; j++)
136                 {
137                     int tmp = (j + 1) * val;
138                     int l = pos[x];
139                     int r = pos[R[x]];
140                     add(pos[x], tmp,((dep[x] + 1)%k + j)%k);
141                     add(pos[R[x]] + 1, -tmp,((dep[x] + 1)%k + j)%k);
142                 }
143             }
144             if (op == 2)
145             {
146                 printf("%d\n",sum(pos[x],(dep[x]-dep[1] + 1) % k));
147             }
148         }
149     }
150     return 0;
151 }
时间: 2024-10-27 17:29:43

FZU2176---easy problem (树链剖分)的相关文章

FZOJ 2176 easy problem ( 树链剖分 )

题目链接~~> 做题感悟:感觉做多了树链剖分的题目,有很多是树链剖分 + 想法.. 解题思路: 这题非常明显的一点就是 k 非常小,那就是告诉你能够从 k 入手,如何入手呢 ? 观察能够发现无非最多是 k 类点 ,0 ~ k-1 ,分别表示与根的距离模 k .这样就能够把点分类加权值,可是每一个线段树里存的还是全部元素,查询的时候相应查找. 代码: #include<iostream> #include<sstream> #include<map> #includ

HDU 5296 Annoying Problem 树链剖分 LCA 倍增法

HDU 5296 Annoying Problem 题目链接:hdu 5296 题意:在一棵给定的具有边权的树,一个节点的集合S(初始为空),给定Q个操作,每个操作增加或删除S中的一个点,每个操作之后输出使集合S中所有点联通的最小子树的边权和. 思路:最小子树上的节点的充要条件: 节点为(S集合中所有点的LCA)的子节点: 节点有一个子孙为S集合中的点. 那么我们给每个节点都开一个标记数组,初始为零,每加入一个节点,就把从这个节点到根节点路径上的点的值都+1,反之-1,这样通过对每个单节点值的查

HDU 4729 An Easy Problem for Elfness(树链剖分边权+二分)

题意 链接:https://cn.vjudge.net/problem/HDU-4729 给你n个点,然你求两个点s和t之间的最大流.而且你有一定的钱k,可以进行两种操作 1.在任意连个点之间建立一个单位1的流,费用a 2.将原先的流扩大1个单位,费用b 思路 题目已经说了是一棵树,那么树上两点的最大流就是两点路径上的最小值.其实两种操作各一次对最大流的贡献是相等的.我们分类讨论: 如果a<=b,直接算第一种方案即可,直接给s.t连一条边,对答案的贡献是k/a. 如果a>b,分两种情况.如果k

Codeforces Round #425 (Div. 2) Problem D Misha, Grisha and Underground (Codeforces 832D) - 树链剖分 - 树状数组

Misha and Grisha are funny boys, so they like to use new underground. The underground has n stations connected with n - 1 routes so that each route connects two stations, and it is possible to reach every station from any other. The boys decided to h

(中等) HDU 5293 Tree chain problem,树链剖分+树形DP。

Problem Description Coco has a tree, whose vertices are conveniently labeled by 1,2,…,n.There are m chain on the tree, Each chain has a certain weight. Coco would like to pick out some chains any two of which do not share common vertices.Find out the

HDOJ 5293 Tree chain problem LCA+树链剖分+树形DP

[题意] 给定一颗树上的几条链和每条链的权值,求能取出的不含有公共节点的链的最大权值.... [解] 预处理每条链的lca 树形DP, d[i]表示取到这个节点时可以得到的最大值 , sum[i]=sigma( d[k] | k 是i的子节点) 如果不取i  d[i]=sum[i] 如果取i , e是lca为i的链则 d[i]=max(d[i],e的权值+sigma(sum[k])-sigma(d[k]))  k为树链上的点 可以用树链剖分+树装数组在nlogn的时间复杂度内求链上的值 Tree

【bzoj4999】This Problem Is Too Simple! 树链剖分+动态开点线段树

题目描述 给您一颗树,每个节点有个初始值. 现在支持以下两种操作: 1. C i x(0<=x<2^31) 表示将i节点的值改为x. 2. Q i j x(0<=x<2^31) 表示询问i节点到j节点的路径上有多少个值为x的节点. 输入 第一行有两个整数N,Q(1 ≤N≤ 100,000:1 ≤Q≤ 200,000),分别表示节点个数和操作个数. 下面一行N个整数,表示初始时每个节点的初始值. 接下来N-1行,每行两个整数x,y,表示x节点与y节点之间有边直接相连(描述一颗树).

hdu4729 树链剖分+二分

An Easy Problem for Elfness Time Limit: 5000/2500 MS (Java/Others)    Memory Limit: 65535/65535 K (Java/Others)Total Submission(s): 1235    Accepted Submission(s): 257 Problem Description Pfctgeorge is totally a tall rich and handsome guy. He plans t

树链剖分简(单)介(绍)

树链剖分可以算是一种数据结构(一大堆数组,按照这个意思,主席树就是一大堆线段树).将一棵树分割成许多条连续的树链,方便完成一下问题: 单点修改(dfs序可以完成) 求LCA(各种乱搞也可以) 树链修改(修改任意树上两点之间的唯一路径) 树链查询 (各种操作)  前两个内容可以用其他方式解决,但是下面两种操作倍增.st表,dfs序就很难解决(解决当然可以解决,只是耗时长点而已).下面开始步入正题. 树链剖分的主要目的是分割树,使它成一条链,然后交给其他数据结构(如线段树,Splay)来进行维护.常