zoukankan      html  css  js  c++  java
  • HDU 5044 Tree 树链剖分

    Tree

    Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)

    【Problem Description】
       You are given a tree (an acyclic undirected connected graph) with N nodes. The tree nodes are numbered from 1 to N
       There are N - 1 edges numbered from 1 to N - 1.
       Each node has a value and each edge has a value. The initial value is 0.
       There are two kind of operation as follows:
       ●  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.
       After finished M operation on the tree, please output the value of each node and edge.
     
    【Input】
       The first line of the input is T (1 ≤ T ≤ 20), which stands for the number of test cases you need to solve.
       The first line of each case contains two integers N ,M (1 ≤ N, M ≤105),denoting the number of nodes and operations, respectively.
       The next N - 1 lines, each lines contains two integers u, v(1 ≤ u, v ≤ N ), denote there is an edge between u,v and its initial value is 0.
       For the next M line, contain instructions “ADD1 u v k” or “ADD2 u v k”. (1 ≤ u, v ≤ N, -105 ≤ k ≤ 105)
     
    【Output】
       For each test case, print a line “Case #t:”(without quotes, t means the index of the test case) at the beginning.
       The second line contains N integer which means the value of each node.
       The third line contains N - 1 integer which means the value of each edge according to the input order.
     
    【Sample Input】
    2
    4 2
    1 2
    2 3
    2 4
    ADD1 1 4 1
    ADD2 3 4 2
    4 2
    1 2
    2 3
    1 4
    ADD1 1 4 5
    ADD2 3 2 4
    【Sample Output】
    Case #1:
    1 1 0 1
    0 2 2
    Case #2:
    5 0 0 5
    0 4 0


    【题意】

    维护一棵树,操作是对某两点路径上的所有点的权值加上某个值,或者对某两点路径上的所有边的权值加上某个值。

    【分析】

    Kuang神出题的时候特别为这题卡了数据,LCT目测是不够过的,用树链剖分转成线性加输入挂也是勉强过,4700ms左右,那种1000~2000ms左右的算法不太明白是怎么写的。

    1.维护两点路径上的点权值是树链剖分的基本操作

    2.维护两点路径上的边权值需要在剖分的时候直接按照边的情况,直接用子结点的序号来代表一条边,然后做好边原本序号的记录

    一般的树链剖分是直接用树状数组,但是由于本题的最终结果要求的是输出所有点和所有边的权值,因此采用树状数组每次求一次sum来得到每个点的值就有点浪费效率了。

    可以参考原本树状数组的方式,直接用一个普通的数组来记录情况,在起点+value,在终点后的一个点-value,表示对整段线段完成加权值;最终求和的时候只需要从头向后扫一遍,求出每个点的sum(i)即可

      1 /* ***********************************************
      2 MYID    : Chen Fan
      3 LANG    : G++
      4 PROG    : HDU 5044
      5 ************************************************ */
      6 
      7 #include <iostream>
      8 #include <cstdio>
      9 #include <cstring>
     10 #include <algorithm>
     11 
     12 using namespace std;
     13 
     14 #define MAXN (int)1E5+10
     15 #define MAXM (int)2E5+10
     16 
     17 int son[MAXN],ans[MAXN];
     18 int father[MAXN],size[MAXN],level[MAXN],data[MAXN],top[MAXN];
     19 int start[MAXN];
     20 
     21 typedef struct nod
     22 {
     23     int to,next,no;
     24 } node;
     25 node edge[MAXM];
     26 int last,n;
     27 
     28 void addedge(int from,int to,int k)
     29 {
     30     last++;
     31     edge[last].to=to; 
     32     edge[last].next=start[from];
     33     edge[last].no=k;
     34     start[from]=last;
     35 }
     36 
     37 int c[MAXN],pos[MAXN],fp[MAXN];
     38 int ec[MAXN],epos[MAXN],fep[MAXN];
     39 int tot;
     40 
     41 int q[MAXN];
     42 void bfs()
     43 {
     44     int head=1,tail=1;
     45     q[1]=1;
     46     level[1]=0;
     47     father[1]=0;
     48 
     49     while(head<=tail)
     50     {
     51         int now=q[head];
     52         size[now]=1;
     53         for (int i=start[now];i;i=edge[i].next)
     54         {
     55             int temp=edge[i].to;
     56             if (temp!=father[now])
     57             {
     58                 father[temp]=now;
     59                 fep[temp]=edge[i].no;
     60                 level[temp]=level[now]+1;
     61                 tail++;
     62                 q[tail]=temp;
     63             }
     64         }
     65         head++;
     66     }
     67     for (int i=n;i>=1;i--)
     68     {
     69         int now=q[i];
     70         if (father[now])
     71         {
     72             size[father[now]]+=size[now];
     73             if (son[father[now]]==0||size[now]>size[son[father[now]]])
     74             son[father[now]]=now;
     75         }
     76     }
     77     for (int i=1;i<=n;i++)
     78     {
     79         int now=q[i];
     80         if (son[father[now]]==now) top[now]=top[father[now]];
     81         else 
     82         {
     83             top[now]=now;
     84             while(now)
     85             {
     86                 tot++;
     87                 pos[now]=tot;
     88                 fp[tot]=now;
     89                 now=son[now];
     90             }
     91         }
     92     }
     93 }
     94 
     95 void change(int x,int y,int value)
     96 {
     97     while(top[x]!=top[y])
     98     {
     99         if (level[top[x]]<level[top[y]]) swap(x,y);
    100     
    101         c[pos[top[x]]]+=value;
    102         c[pos[x]+1]-=value;
    103 
    104         x=father[top[x]];
    105     }
    106     if (level[x]>level[y]) swap(x,y);
    107     
    108     c[pos[x]]+=value;
    109     c[pos[y]+1]-=value;
    110 }
    111 
    112 void change_edge(int x,int y,int value)
    113 {
    114     while(top[x]!=top[y])
    115     {
    116         if (level[top[x]]<level[top[y]]) swap(x,y);
    117     
    118         ec[pos[top[x]]]+=value;
    119         ec[pos[x]+1]-=value;
    120 
    121         x=father[top[x]];
    122     }
    123     if (level[x]>level[y]) swap(x,y);
    124     
    125     ec[pos[son[x]]]+=value;
    126     ec[pos[y]+1]-=value;
    127 }
    128 
    129 int INT() {
    130     char ch;
    131     int res;
    132     bool neg;
    133     while (ch = getchar(), !isdigit(ch) && ch != '-')
    134         ;
    135     if (ch == '-') {
    136         neg = true;
    137         res = 0;
    138     } else {
    139         neg = false;
    140         res = ch - '0';
    141     }
    142     while (ch = getchar(), isdigit(ch))
    143         res = res * 10 + ch - '0';
    144     return neg ? -res : res;
    145 }
    146 
    147 int main()
    148 {
    149     freopen("5044.txt","r",stdin);
    150 
    151     int t;
    152     t=INT();
    153 
    154     for (int tt=1;tt<=t;tt++)
    155     {
    156         printf("Case #%d:
    ",tt);
    157 
    158         int m;
    159         n=INT();m=INT();
    160     
    161         memset(start,0,sizeof(start));
    162         last=0;
    163         for (int i=1;i<n;i++)
    164         {
    165             int u,v;
    166             u=INT();
    167             v=INT();
    168             addedge(u,v,i);
    169             addedge(v,u,i);
    170         }
    171 
    172         memset(son,0,sizeof(son));
    173         tot=0;
    174         bfs();
    175 
    176         memset(c,0,sizeof(c));
    177         memset(ec,0,sizeof(ec));
    178 
    179         for (int i=1;i<=m;i++)
    180         {
    181             char s;
    182             int c1,c2,k;
    183             s=getchar();
    184             while (!isdigit(s)) s=getchar();
    185             c1=INT();
    186             c2=INT();
    187             k=INT();
    188             if (s=='1') change(c1,c2,k);
    189             else change_edge(c1,c2,k);
    190         }
    191 
    192         int ss=0;
    193         for (int i=1;i<=n;i++)
    194         {
    195             ss+=c[i];
    196             ans[fp[i]]=ss;
    197         }
    198         printf("%d",ans[1]);
    199         for (int i=2;i<=n;i++) 
    200         {
    201             putchar(' ');
    202             printf("%d",ans[i]);
    203         }
    204         putchar('
    ');
    205 
    206         ss=0;
    207         for (int i=1;i<=n;i++)
    208         {
    209             ss+=ec[i];
    210             ans[fep[fp[i]]]=ss;
    211         }
    212         if (n>1) printf("%d",ans[1]);
    213         for (int i=2;i<n;i++) 
    214         {
    215             putchar(' ');
    216             printf("%d",ans[i]);
    217         }
    218         putchar('
    ');
    219         
    220     }
    221 
    222     return 0;
    223 }
    View Code
  • 相关阅读:
    IOS8定位
    ios通讯录基本操作2014-12月版
    ios悬浮按钮的实现
    MartinLiPageScrollView广告栏实现
    ios分享(友盟分享)
    vue2.0路由-适合刚接触新手简单理解
    git链接GitHub命令及基本操作
    Node
    JS数组sort()排序
    原生JS获取CSS样式并修改
  • 原文地址:https://www.cnblogs.com/jcf94/p/4488801.html
Copyright © 2011-2022 走看看