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:\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 }

 

你可能感兴趣的:(AS)