• 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 }
  • 相关阅读:
    研究生数学建模历年题目汇总
    【20220902】成年人的美好
    【20220831】恶梦
    【20220827】连岳摘抄
    【20220903】连岳摘抄
    【20220904】勇气之笔
    【20220905】珍惜时光
    【20220901】连岳摘抄
    【20220830】哺乳
    【力扣 056】123. 买卖股票的最佳时机 III
  • 原文地址:https://www.cnblogs.com/oneshot/p/4106502.html
Copyright © 2020-2023  润新知