zoukankan      html  css  js  c++  java
  • RMQ与LCA入门&&ST算法的运用

    RMQ

    RMQ (Range Minimum/Maximum Query)问题是指:对于长度为n的数列A,回答若干询问RMQ(A,i,j)(i,j<=n),返回数列A中下标在i,j里的最小(大)值,也就是说,RMQ问题是指求区间最值的问题。——百度百科

    举个例子:在1 0 4 99 8 5这一串数中求第2个数到第5个数的最小值。

    有什么办法?

    最简单的莫过于循环一次,时间为O(N).但如果有许多个询问呢?

    这时就要用到ST算法了。利用动规预处理出每一段的最值,对于每个询问,只要O(1)的时间便能得出答案。

    动规如下:f[i][j]表示从第i个位置开始的2^j个数中的最小值。转移方程如下:

    f[i][j]=min(f[i][j-1],f[i+2^(j-1)][j-1])

    这样,对于每个查询x,y(x<y)(在第x个位置到第y个位置的最值),答案就是

    min(f[x][j],f[y-2^(j)+1][j])(其中j是log2(y-x+1))
    ∵[x,x+2^j]与[y-2^(j)]都是[x,y]的子区间且[x,x+2^j]U[y-2^(j)]=[x,y]。

    至此RMQ问题就解决了,时间复杂度为O(nlogn)+O(1)*q(其中q为询问数量)

    当然还有其他的方法这里就不讨论了

    LCA

    最近公共祖先(Least Common Ancestors)LCA简介:对于有根树T的两个结点u、v,最近公共祖先LCA(T,u,v)表示一个结点x,满足x是u、v的祖先且x的深度尽可能大。另一种理解方式是把T理解为一个无向无环图,而LCA(T,u,v)即u到v的最短路上深度最小的点。——百度百科

    求LCA的其中一种算法便是转换成RMQ,利用ST算法求解。具体做法如下: 将这棵树用深度优先遍历,每次遍历一个点(包括回溯)都添加进数组里面。找到所询问的点第一次在其出现的位置,两个位置所夹的点中深度最小的即为所求。

    如图求3与6的LCA。首先利用深度优先遍历得到一个数列:1,2,3,2,4,5,6

    找到3第一次出现以及6第一次出现的位置。所夹数列即为3,2,4,5,6。其中深度最小的点就是他们的LCA,也就是2.

    例题

    (这里就直接贴代码了,详细题解可见这里

    1、hdu2586:

    View Code
     1 #include <iostream>
     2 #include <cmath>
     3 #include <algorithm>
     4 using namespace std;
     5 struct node{
     6        int link,dt;
     7        node *next;
     8 }*son[40009],ES[100009];
     9 int n,m,EC,t,f[100009][20],bit[20],lg,
    10     fir[40009],enter[100009],dis[40009],deep[40009],lca[100009][20];
    11 void addedge(int x,int y,int z)
    12 {
    13      ES[++EC].next=son[x];
    14      son[x]=ES+EC;
    15      son[x]->link=y;
    16      son[x]->dt=z;
    17 }
    18 void tr(int fa,int v)
    19 {
    20      enter[++t]=v;
    21      if (!fir[v]) fir[v]=t;
    22      for (node *tmp=son[v];tmp;tmp=tmp->next)
    23          if (tmp->link!=fa){
    24             int u=tmp->link;
    25             deep[u]=deep[v]+1;
    26             dis[u]=dis[v]+tmp->dt;
    27             tr(v,u);
    28             enter[++t]=v;
    29             }
    30 }
    31 void dp()
    32 {
    33      for (int i=1;i<=2*n-1;++i) f[i][0]=deep[enter[i]],lca[i][0]=i;
    34      for (int j=1;j<=lg;++j)
    35          for (int i=1;i<=2*n-bit[j]+1;++i)
    36              if (f[i][j-1]<f[i+bit[j-1]][j-1]) f[i][j]=f[i][j-1],lca[i][j]=lca[i][j-1];
    37              else f[i][j]=f[i+bit[j-1]][j-1],lca[i][j]=lca[i+bit[j-1]][j-1];
    38 }
    39 int main()
    40 {
    41 #ifndef ONLINE_JUDGE
    42     freopen("hdu2586.in","r",stdin);freopen("hdu2568.out","w",stdout);
    43 #endif
    44     bit[0]=1;
    45     for (int i=1;i<=19;++i) bit[i]=bit[i-1]*2;
    46     ios::sync_with_stdio(false);
    47     int T;
    48     cin>>T;
    49     for (int AC=T;AC;--AC){
    50         EC=0;
    51         t=0;
    52         deep[1]=1;
    53         memset(f,0,sizeof(f));
    54         memset(fir,0,sizeof(fir));
    55         memset(son,0,sizeof(son));
    56         cin>>n>>m;
    57         lg=floor(log2(2*n-1));
    58         int x,y,z,k;
    59         for (int i=n-1;i;--i){
    60             cin>>x>>y>>z;
    61             addedge(x,y,z);
    62             addedge(y,x,z);
    63             }
    64         tr(0,1);
    65         dp();
    66         for (int i=m;i;--i){
    67             cin>>x>>y;
    68             int ans=dis[x]+dis[y];
    69             x=fir[x];y=fir[y];
    70             if (x>y) swap(x,y); 
    71             lg=floor(log2(y-x+1));
    72             if (f[x][lg]<f[y-bit[lg]+1][lg]) k=lca[x][lg];
    73             else k=lca[y-bit[lg]+1][lg];
    74             cout<<ans-2*dis[enter[k]]<<endl;
    75             }
    76         }
    77 #ifndef ONLINE_JUDGE
    78     fclose(stdin);fclose(stdout);
    79 #endif
    80 }

    2、poj3264:

    #include <cstdio>
    #include <cmath>
    #include <algorithm>
    #include <iostream>
    using namespace std;
    int n,q,h[50009],Fmin[50009][17],Fmax[50009][17],lg,bit[17];
    int main()
    {
    #ifndef ONLINE_JUDGE
        freopen("lineup.in","r",stdin);freopen("lineup.out","w",stdout);
    #endif
        scanf("%d%d",&n,&q);
        bit[0]=1;
        for (int i=1;i<=16;++i) bit[i]=2*bit[i-1];
        for (int i=1;i<=n;++i){
            scanf("%d",&h[i]);
            Fmin[i][0]=Fmax[i][0]=h[i];
            }
        lg=floor(log10((double)n)/log10((double)2));
        for (int j=1;j<=lg;++j)
            for (int i=1;i<=n+1-bit[j];++i){
                Fmin[i][j]=min(Fmin[i][j-1],Fmin[i+bit[j-1]][j-1]);
                Fmax[i][j]=max(Fmax[i][j-1],Fmax[i+bit[j-1]][j-1]);
                }
        int x,y;
        for (int i=1;i<=q;++i){
            scanf("%d%d",&x,&y);
            if (x>y) swap(x,y);
            lg=floor(log10((double)(y-x+1))/log10((double)2));
            printf("%d\n",max(Fmax[x][lg],Fmax[y-bit[lg]+1][lg])-
            min(Fmin[x][lg],Fmin[y-bit[lg]+1][lg]));
            }
    #ifndef ONLINE_JUDGE
        fclose(stdin);fclose(stdout);
    #endif
    }
    
  • 相关阅读:
    安装RabbitMQ说明
    死锁
    管程
    MybatisPlus快速开发
    了解Mybatis-Plus
    查看监听器状态
    The command supports no service 解决办法
    任务11 Arduino光照报警器
    任务10 测试光的强度实验
    任务9 Arduino光敏实验
  • 原文地址:https://www.cnblogs.com/lazycal/p/2633486.html
Copyright © 2011-2022 走看看