• C++之路进阶——codevs2460(树的统计)


    2460 树的统计

     

    2008年省队选拔赛浙江

     时间限制: 2 s
     空间限制: 128000 KB
     题目等级 : 大师 Master
     
     
     
    题目描述 Description

    一棵树上有n个节点,编号分别为1到n,每个节点都有一个权值w。

    我们将以下面的形式来要求你对这棵树完成一些操作:

    1. I.                    CHANGE u t : 把结点u的权值改为t
    2. II.                 QMAX u v: 询问从点u到点v的路径上的节点的最大权值
    3. III.               QSUM u v: 询问从点u到点v的路径上的节点的权值和

     

    注意:从点u到点v的路径上的节点包括u和v本身

    输入描述 Input Description

    输入文件的第一行为一个整数n,表示节点的个数。

           接下来n – 1行,每行2个整数a和b,表示节点a和节点b之间有一条边相连。

           接下来n行,每行一个整数,第i行的整数wi表示节点i的权值。

           接下来1行,为一个整数q,表示操作的总数。

    接下来q行,每行一个操作,以“CHANGE u t”或者“QMAX u v”或者“QSUM u v”的形式给出。

    输出描述 Output Description

           对于每个“QMAX”或者“QSUM”的操作,每行输出一个整数表示要求输出的结果。

    样例输入 Sample Input

    4

    1 2

    2 3

    4 1

    4 2 1 3

    12

    QMAX 3 4

    QMAX 3 3

    QMAX 3 2

    QMAX 2 3

    QSUM 3 4

    QSUM 2 1

    CHANGE 1 5

    QMAX 3 4

    CHANGE 3 6

    QMAX 3 4

    QMAX 2 4

    QSUM 3 4

    样例输出 Sample Output

    4

    1

    2

    2

    10

    6

    5

    6

    5

    16

    数据范围及提示 Data Size & Hint

    对于100%的数据,保证1<=n<=30000,0<=q<=200000;中途操作中保证每个节点的权值w在-30000到30000之间。

    题解

         裸的树链剖分...

          

    树链剖分就是把树拆成一系列链,然后用数据结构对链进行维护。

    通常的剖分方法是轻重链剖分,所谓轻重链就是对于节点u的所有子结点v,size[v]最大的v与u的边是重边,其它边是轻边,其中size[v]是以v为根的子树的节点个数,全部由重边组成的路径是重路径,根据论文上的证明,任意一点到根的路径上存在不超过logn条轻边和logn条重路径。

    这样我们考虑用数据结构来维护重路径上的查询,轻边直接查询。

    通常用来维护的数据结构是线段树,splay较少见。

    具体步骤

    预处理

    第一遍dfs求出树每个结点的深度deep[x],其为根的子树大小size[x]

    以及祖先的信息fa[x][i]表示x往上距离为2^i的祖先

    第二遍dfs

    ž根节点为起点,向下拓展构建重链

    选择最大的一个子树的根继承当前重链

    其余节点,都以该节点为起点向下重新拉一条重链

    ž给每个结点分配一个位置编号,每条重链就相当于一段区间,用数据结构去维护。

    把所有的重链首尾相接,放到同一个数据结构上,然后维护这一个整体即可

    修改操作

    ž1、单独修改一个点的权值

    根据其编号直接在数据结构中修改就行了。

    2、修改点u和点v的路径上的权值

    (1)若u和v在同一条重链上

    直接用数据结构修改pos[u]至pos[v]间的值。

    (2)若u和v不在同一条重链上

    一边进行修改,一边将u和v往同一条重链上靠,然后就变成了情况(1)。

    查询操作

    ž查询操作的分析过程同修改操作

    题目不同,选用不同的数据结构来维护值,通常有线段树和splay

    代码:

        树链剖分

      1 #include<cstdio>
      2 #include<iostream>
      3 #include<cstring>
      4 #define INF 0x7fffffff
      5 #define N 30005
      6 #define M 60005
      7 
      8 using namespace std;
      9 
     10 int n,q,cnt,sz;
     11 int fa[N][15],v[N],deep[N],size[N],head[N];
     12 int pos[N],belong[N];
     13 bool vis[N];
     14 struct node
     15     {
     16      int to;
     17      int next;
     18     }e[M];
     19     
     20 struct ss
     21      {
     22        int l;
     23        int r;
     24        int mx;
     25        int sum;
     26      }t[100005];
     27      
     28 void insert(int u,int v)
     29    {
     30     e[++cnt].to=v; e[cnt].next=head[u]; head[u]=cnt;
     31     e[++cnt].to=u; e[cnt].next=head[v]; head[v]=cnt;
     32    }
     33     
     34 void inint()
     35    {
     36      scanf("%d",&n);
     37      for (int i=1;i<n;i++)
     38         {
     39           int x,y;
     40           scanf("%d%d",&x,&y);
     41           insert(x,y);
     42         }
     43     for (int i=1;i<=n;i++) scanf("%d",&v[i]);
     44    }
     45    
     46 void getree(int x)
     47    {
     48      size[x]=1;
     49      vis[x]=1;
     50      for (int i=1;i<=14;i++)
     51         {
     52           if (deep[x]<(1<<i)) break;
     53           fa[x][i]=fa[fa[x][i-1]][i-1];
     54         }
     55     for (int i=head[x];i;i=e[i].next)
     56         {
     57           if (vis[e[i].to]) continue;
     58           deep[e[i].to]=deep[x]+1;
     59           fa[e[i].to][0]=x;
     60           getree(e[i].to);
     61           size[x]+=size[e[i].to];
     62         }
     63    }
     64    
     65 void dfs(int x,int chain)
     66    {
     67     int k=0; 
     68     sz++;
     69     pos[x]=sz;
     70     belong[x]=chain;
     71     for (int i=head[x];i;i=e[i].next)
     72         if (deep[e[i].to]>deep[x]&&size[e[i].to]>size[k])
     73            k=e[i].to;
     74     if (k==0) return;
     75     dfs(k,chain);
     76     for (int i=head[x];i;i=e[i].next)
     77        if (deep[e[i].to]>deep[x]&&k!=e[i].to)
     78            dfs(e[i].to,e[i].to);
     79    }
     80    
     81 int lca(int x,int y)
     82   {
     83     if (deep[x]<deep[y]) swap(x,y);
     84     int t=deep[x]-deep[y];
     85     for (int i=0;i<=14;i++)
     86        if ((1<<i)&t) x=fa[x][i];
     87     for (int i=14;i>=0;i--)
     88          if (fa[x][i]!=fa[y][i])
     89               {
     90                x=fa[x][i];
     91                y=fa[y][i];
     92               }
     93     if (x==y) return x;
     94      else return fa[x][0];
     95   } 
     96   
     97 void build(int k,int l,int r)
     98    {
     99      t[k].l=l;
    100      t[k].r=r;
    101      if (l==r) return;
    102      int mid=(l+r)>>1;
    103      build(k<<1,l,mid);
    104      build(k<<1|1,mid+1,r);
    105    }
    106    
    107 void change(int k,int x,int y)
    108    {
    109       int l=t[k].l,r=t[k].r,mid=(l+r)>>1;
    110       if (l==r)
    111           {
    112             t[k].sum=t[k].mx=y;
    113             return;
    114           }
    115       if (x<=mid) change(k<<1,x,y);
    116          else change(k<<1|1,x,y);
    117       t[k].sum=t[k<<1].sum+t[k<<1|1].sum;
    118       t[k].mx=max(t[k<<1].mx,t[k<<1|1].mx);
    119    }
    120    
    121 int find_sum(int k,int x,int y)
    122    {
    123      int l=t[k].l,r=t[k].r,mid=(l+r)>>1;
    124       if (l==x&&y==r) return t[k].sum;
    125       if (y<=mid) return find_sum(k<<1,x,y);
    126          else if (x>mid) return find_sum(k<<1|1,x,y);
    127                else return find_sum(k<<1,x,mid)+find_sum(k<<1|1,mid+1,y);
    128    }
    129    
    130 int find_mx(int k,int x,int y)
    131    {
    132      int l=t[k].l,r=t[k].r,mid=(l+r)>>1;
    133      if (l==x&&r==y) return t[k].mx;
    134      if (y<=mid) return find_mx(k<<1,x,y);
    135         else if (x>mid) return find_mx(k<<1|1,x,y);
    136                else  return max(find_mx(k<<1,x,mid),find_mx(k<<1|1,mid+1,y));
    137    }
    138    
    139 int solve_mx(int x,int f)
    140    {
    141       int mx=-INF;
    142       while(belong[x]!=belong[f])
    143          {
    144            mx=max(mx,find_mx(1,pos[belong[x]],pos[x]));
    145            x=fa[belong[x]][0];
    146          }
    147      mx=max(mx,find_mx(1,pos[f],pos[x]));
    148      return mx;
    149    }
    150    
    151 int solve_sum(int x,int f)
    152    {
    153     int sum=0;
    154     while (belong[x]!=belong[f])
    155        {
    156          sum+=find_sum(1,pos[belong[x]],pos[x]);
    157          x=fa[belong[x]][0];
    158        }
    159     sum+=find_sum(1,pos[f],pos[x]);
    160     return sum;
    161    }
    162    
    163 void solve()
    164   {
    165     build(1,1,n);
    166     for (int i=1;i<=n;i++)
    167       change(1,pos[i],v[i]);
    168     scanf("%d",&q);
    169     char ch[6];
    170     for (int i=1;i<=q;i++)
    171        {
    172           int x,y;
    173           scanf("%s%d%d",ch,&x,&y);
    174           if (ch[0]=='C')
    175               {
    176                 v[x]=y;
    177                 change(1,pos[x],y);
    178               }
    179              else
    180               {
    181                 int t=lca(x,y);
    182                 if (ch[1]=='M')
    183                    printf("%d
    ",max(solve_mx(x,t),solve_mx(y,t)));
    184                  else 
    185                    printf("%d
    ",solve_sum(x,t)+solve_sum(y,t)-v[t]);
    186               }
    187        }
    188   }
    189   
    190 int main()
    191   {
    192     inint();
    193     getree(1);
    194     dfs(1,1);
    195     solve();
    196     return 0;
    197   }

    块状树:

     1 #include<bits/stdc++.h>
     2 #define maxn (int)1e5+10
     3 
     4 using namespace std;
     5 
     6 vector<int>g[maxn],ge[maxn];
     7 int cnt,sqrtn,n,m;
     8 int w[maxn],sum[maxn],mx[maxn],fa[maxn],deep[maxn],bel[maxn],size[maxn];
     9 
    10 void dfs(int u) 
    11    {
    12     for(int i=0;i<g[u].size();i++)
    13        {
    14         int v=g[u][i];
    15         if(v==fa[u])continue;
    16         fa[v]=u;
    17         deep[v]=deep[u]+1;
    18         if(size[bel[u]]<sqrtn)
    19          {
    20             size[bel[u]]++;bel[v]=bel[u];
    21             ge[u].push_back(v);
    22         }
    23         dfs(v);    
    24     }
    25 }
    26    
    27 void dfs(int u,int s,int maxx) 
    28   {
    29     s+=w[u];
    30     sum[u]=s;
    31     maxx=max(maxx,w[u]);
    32     mx[u]=maxx;
    33     for(int i=0;i<ge[u].size();i++)
    34        dfs(ge[u][i],s,maxx);
    35 }
    36 
    37 void change(int u,int ww)
    38    {
    39     w[u]=ww;
    40     if(bel[u]==u) dfs(u,0,INT_MIN);
    41     else dfs(u,sum[fa[u]],mx[fa[u]]);  
    42 } 
    43 
    44 pair<int,int> qsumax(int u,int v)
    45    { 
    46     int s=0,maxx=INT_MIN;
    47     while(u!=v){
    48         if(deep[u]<deep[v])swap(u,v);
    49         if(bel[u]==bel[v])
    50           {
    51             s+=w[u];maxx=max(maxx,w[u]);
    52             u=fa[u];
    53         }
    54          else
    55            {
    56             if(deep[bel[u]]<deep[bel[v]])swap(u,v);
    57             s+=sum[u],maxx=max(maxx,mx[u]);
    58             u=fa[bel[u]];
    59         }
    60     }
    61     s+=w[u],maxx=max(maxx,w[u]);
    62     return pair<int,int>(s,maxx);
    63 }
    64     
    65 int main()
    66     {
    67        scanf("%d",&n);    
    68        sqrtn=sqrt(n);     
    69        for (int i=1;i<n;i++)
    70          {
    71                int u,v;
    72                scanf("%d%d",&u,&v);
    73                g[u].push_back(v);
    74               g[v].push_back(u);
    75              }
    76       for (int i=1;i<=n;i++)
    77         scanf("%d",w+i),bel[i]=i,size[i]=1;
    78       dfs(1);                  
    79       int q;
    80       for(int i=1;i<=n;i++)if(bel[i]==i)
    81            dfs(i,0,INT_MIN);
    82       scanf("%d",&q);
    83       while (q--)
    84         {
    85           int x,y;    
    86           char op[5];     
    87           scanf("%s%d%d",op,&x,&y);    
    88           if(op[0]=='C') change(x,y);
    89             else
    90             {
    91               pair<int,int>anss=qsumax(x,y);
    92               if(op[1]=='M')
    93                      printf("%d
    ",anss.second);
    94                else printf("%d
    ",anss.first);            
    95                 }
    96     }    
    97       return 0;
    98     }
  • 相关阅读:
    centos6.5用tomcat安装jenkins
    maridb安装审计audit插件
    centos6.5安装配置supervisor
    centos mail使用外部SMTP发送邮件
    netsh导入导出IPSec配置策略
    nfs mount:reason given by server: Permission denied
    oracle备份脚本
    修改mysql root账号密码
    python生成二维码
    lvm的vg扩容
  • 原文地址:https://www.cnblogs.com/grhyxzc/p/5134397.html
Copyright © 2020-2023  润新知