关于均值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 }
实现较为复杂,不到特殊情况不推荐使用