zoukankan      html  css  js  c++  java
  • RMQ问题

    RMQ问题

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

    主要方法(线段树,ST表,LCA)

    1.线段树

    支持修改,时间复杂度:预处理O(n),查询O(log(n))

    例:HDU1754

    #include<stdio.h>
    #include<string.h>
    #include<algorithm>
    #include<math.h>
    #include<string>
    #include<queue>
    #include<map>
    #include<stack>
    #include<iostream>
    #define INF 0x3f3f3f3f
    typedef long long ll;
    using namespace std;
    //定义 
    #define maxn 500007  //元素总个数  
    int Max[maxn<<2],Add[maxn<<2];//Max求最大值,Add为懒惰标记   
    int A[maxn],n,ANS;//存原数组数据下标[1,n] 
    //建树
    //PushUp函数更新节点信息 ,这里是求最大值 
    void PushUp(int rt){Max[rt]=max(Max[rt<<1],Max[rt<<1|1]);}  
    //Build函数建树   
    void Build(int l,int r,int rt){ //l,r表示当前节点区间,rt表示当前节点编号  
        if(l==r) {//若到达叶节点   
            Max[rt]=A[l];//储存数组值   
            return;  
        }  
        int m=(l+r)>>1;  
        //左右递归   
        Build(l,m,rt<<1);  
        Build(m+1,r,rt<<1|1);  
        //更新信息   
        PushUp(rt);  
    }   
    //点修改
    void Update(int L,int C,int l,int r,int rt){//l,r表示当前节点区间,rt表示当前节点编号  
        if(l==r){//到叶节点,修改   
            Max[rt]=C;  
            return;  
        }  
        int m=(l+r)>>1;  
        //根据条件判断往左子树调用还是往右   
        if(L <= m) Update(L,C,l,m,rt<<1);  
        else       Update(L,C,m+1,r,rt<<1|1);  
        PushUp(rt);//子节点更新了,所以本节点也需要更新信息   
    }   
    
    //区间查询
    int Query(int L,int R,int l,int r,int rt){//L,R表示操作区间,l,r表示当前节点区间,rt表示当前节点编号  
        if(L <= l && r <= R){  
            //在区间内,直接返回   
            return ANS=max(Max[rt],ANS);  
        }  
        int m=(l+r)>>1;   
          
        //累计答案    
        if(L <= m) Query(L,R,l,m,rt<<1);  
        if(R >  m) Query(L,R,m+1,r,rt<<1|1);  
        return ANS;  
    }   
    int main()
    {
    		int m,u,v;
    	while(cin>>n>>m)
    	{
    		memset(Max,0,sizeof(Max));
    		memset(Add,0,sizeof(Add));
    	for(int i=1;i<=n;i++)
    	{
    		scanf("%d",&A[i]);
    	} 
    	Build(1,n,1);
    	string str;
    	for(int i=1;i<=m;i++)
    	{
    		cin>>str;
    		if(str[0]=='Q')
    		{
    			ANS=0;
    			scanf("%d%d",&u,&v);
    			printf("%d
    ",Query(u,v,1,n,1));
    		}
    		else if(str[0]=='U')
    		{
    			scanf("%d%d",&u,&v);
    			Update(u,v,1,n,1);
    		}
    	}
    	}
    }
    

    2.ST表

    以倍增思想为基础,不能在线修改,适合离线RMQ问题
    时间复杂度: 预处理O(nlog(n)) 查询O(1)
    预处理:先开辟一个数组(f[i][j])表示从第i号节点到第i+2j-1号节点的最大值,即从i号节点开始往后数共2j个节点中的最大值。
    查询:查询x,y之间的最大值,记len为[x,y]区间长度 ,最大值=max((f[x][log {len}],f[y-2^{log{len}}+1][log{len}]))
    具体思路参考这篇博客

    例:洛谷p3865

    #pragma GCC optimize("Ofast")
    #pragma GCC target("avx,avx2,fma")
    #pragma GCC optimize ("unroll-loops")
    #include<stdio.h>
    #include<string.h>
    #include<algorithm>
    #include<math.h>
    #include<string>
    #include<queue>
    #include<map>
    #include<stack>
    #include<iostream>
    #define INF 0x3f3f3f3f
    #define lowbit(a) ((a)&-(a))
    typedef long long ll;
    typedef unsigned long long ull;
    using namespace std;
    int a[110000][30],logg[110000],bin[110000];
    int i,j,k,m,n,o,p,js,jl,x,y,t,lg;
    int my_max(int x,int y)
    {
        if(x>y)return(x);
        else return(y);
    }
    int main()
    {
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++)scanf("%d",&a[i][0]);
    
        bin[0]=1;for(int i=1;i<=30;i++)bin[i]=bin[i-1]*2;
        logg[0]=-1;for(int i=1;i<=n;i++)logg[i]=logg[i/2]+1;
    
        for(int i=1;i<=logg[n];i++)
        for(int j=1;j<=n;j++)
        {
            if(j+bin[i]-1<=n)
            {
                a[j][i]=my_max(a[j][i-1],a[j+bin[i-1]][i-1]);
            }
        } 
    
        for(int i=1;i<=m;i++)
        {
            scanf("%d%d",&x,&y);
            t=y-x+1;lg=logg[t];
            printf("%d
    ",my_max(a[x][lg],a[y-bin[lg]+1][lg]));
        }
    
        return 0;
    }
    

    3.LCA

    太菜了,还不会....以后再写

  • 相关阅读:
    commons-fileupload源码学习心得
    commons-io源码阅读心得
    java反射机制
    构建简单的socket连接池
    maven主仓库中找不到restlet的解决办法
    修改eclipse中web项目的server部署路径
    Errors occurred during the build. Errors running builder 'DeploymentBuilder' on project '项目名'
    JVM中的Stack和Heap
    JVM工作原理和特点
    spring mvc 3.1的自动注入参数遇到的问题
  • 原文地址:https://www.cnblogs.com/qingjielaojiu/p/13529988.html
Copyright © 2011-2022 走看看