FZU2176---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:
",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
",sum(pos[x],(dep[x]-dep[1] + 1) % k));
147             }
148         }
149     }
150     return 0;
151 }
原文地址:https://www.cnblogs.com/oneshot/p/4106502.html