关于均值RMQ和lca浅谈

均值RMQ与lca

这种算法是预处理On,在线O1查询的一个求lca的算法

参考:http://www.docin.com/p-40358260.html

  什么是均值RMQ?

    一个序列A,满足 |A[i]-A[i-1]|=1

  
  正常的st表与均值RMQ的st表关系是怎么样的?

    正常的st表是f[i][j]表示从第i个元素开始的之后2^j的最小值

    均值RMQ的st表,其实就是将序列分块了,每个元素变成了每个块,求法与正常并无什么区别

为了满足时间为On

    每个块的大小len=(log(n))/2;

    块数就是n/len了

    于是求st表的时间就变成了O(n/len * log(n/len))=O(2n/log(n) * (log(n)-log(len)) )=O(2n-2n/log(n)*log(len))=O(n)

    于是求几个块的最小值就可以O1求了

但是对于块内的最小值要怎么求呢?

    每个块的元素=前一个元素+-1,这个+-1的关系可以用二进制表示

      1表示+1,0表示-1

    于是本质不同的块的个数为2^len

    每种块的区间最小值情况可以用len*len的方法暴力求得

    时间为O((2^len)*len*len)=O(sqrt(n)*len*len)<O(n)

这种算法如何求lca?

     有一种预处理O(n log n)查询O1的在线lca写法:dfs序+st表,这里对这种算法不过多阐述

     可以发现,这种dfs序下,每个元素的深度会比前一个元素的深度多1或少1

     于是只要把这里的st表换成均值RMQ的st表即可

 

 

求lca代码

    

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cmath>
 4 using namespace std;
 5 const int M=5e5+9;
 6 int n,m,num=0,id=0,len,block,rt;
 7 int head[M];struct P{int to,ne;}e[M<<1];
 8 int f[M],dep[M],fir[M],a[M<<1];
 9 int L[M<<1],pw[23],b[809][11][11],qz[23],in[M],d[M][23];
10 int read(){
11     int rex=0,f=1;char ch=getchar();
12     while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
13     while(ch>='0'&&ch<='9'){rex=rex*10+ch-'0';ch=getchar();}
14     return rex*f;
15 }
16 int Min(int x,int y){
17     if(x==0)return y;
18     return dep[x]<dep[y]?x:y;
19 }
20 int MIN(int x,int y){
21     return qz[x]<qz[y]?x:y;
22 }
23 void dfs(int u,int fa){
24     f[u]=fa,dep[u]=dep[fa]+1,a[fir[u]=++id]=u;
25     for(int i=head[u];i;i=e[i].ne){
26         int v=e[i].to;
27         if(v!=fa){dfs(v,u);a[++id]=u;}
28     }
29 }
30 int pos(int x,int y,int cnt=0){
31     for(int i=x;i<=y;++i)
32         cnt|=(dep[a[i]]-dep[a[i-1]]==-1)?0:pw[i-x];
33     return cnt;
34 }
35 int query(int l,int r){
36     int x=(l-1)/len;
37     l-=x*len,r-=x*len;++x;
38     return a[(x-1)*len+b[in[x]][l][r]];
39 }
40 int ask(int l,int r){
41     l=fir[l],r=fir[r];
42     if(l>r)swap(l,r);
43     int x=(l-1)/len+1,y=(r-1)/len+1;
44     if(x==y)return query(l,r);
45     x++,y--;int ans=0;
46     if(x<=y){
47         int k=L[y-x+1];
48         ans=Min(d[x][k],d[y-pw[k]+1][k]);
49     }
50     ans=Min(ans,query(l,(x-1)*len));
51     ans=Min(ans,query(y*len+1,r));
52     return ans;
53 }
54 int main(){
55     n=read(),m=read(),rt=read();
56     for(int i=1,u,v;i<n;++i){
57         u=read(),v=read();
58         e[++num]=(P){v,head[u]};head[u]=num;
59         e[++num]=(P){u,head[v]};head[v]=num;
60     }
61     dfs(rt,0);
62     len=log2(id)/2;block=(id-1)/len+1;
63     L[1]=0,pw[0]=1;
64     for(int i=1;i<=20;++i)pw[i]=pw[i-1]<<1;
65     for(int i=2;i<=id;++i)L[i]=L[i>>1]+1;
66     for(int i=1;i<=block;++i)in[i]=pos((i-1)*len+1,i*len);
67     for(int i=0,s=1<<len;i<s;++i){
68         for(int l=1;l<=len;++l)qz[l]=qz[l-1]+((i&pw[l-1])?1:-1);
69         for(int l=1;l<=len;++l){
70             for(int r=l;r<=len;++r){
71                 if(l==r)b[i][l][r]=l;
72                 else b[i][l][r]=MIN(b[i][l][r-1],r);
73             }
74         }
75     }
76     for(int i=1;i<=block;++i)d[i][0]=a[(i-1)*len+b[in[i]][1][len]];
77     for(int j=1;pw[j]<=block;++j){
78         for(int i=1;i+pw[j]-1<=block;++i){
79             d[i][j]=Min(d[i][j-1],d[i+pw[j-1]][j-1]);
80         }
81     }
82     for(int i=1,l,r;i<=m;++i){
83         l=read(),r=read();
84         printf("%d\n",ask(l,r));
85     }
86     return 0;
87 }
View Code

实现较为复杂,不到特殊情况不推荐使用

posted @ 2018-11-27 22:19  sjie  阅读(392)  评论(0编辑  收藏  举报