hdu 5875 Function 二分+rmq

来源:互联网 发布:linux make命令 编辑:程序博客网 时间:2024/05/01 12:04

按照题意每次到当前点右边找比当前点小并且最接近当前点的点p。

如果你能在O(1)的时间里查询[l,r]区间最小值,那么就可以二分查找p。


#include <iostream>#include <cstdio>#include <cstdlib>#include <algorithm>#include <set>#include <cmath>using namespace std;const int maxn=100000+5;int a[maxn];int dp[maxn][32];void ini(int n){    for(int i=1;i<=n;i++)dp[i][0]=a[i];    for(int j=1;j<30;j++){        for(int i=n;i>=1;i--){            if(i+(1<<j-1)<=n)            dp[i][j]=min(dp[i][j-1],dp[i+(1<<j-1)][j-1]);        }    }}inline int rmq(int l,int r){    int k=0;    while(1<<k+1<=r-l+1)k++;    return min(dp[l][k],dp[r-(1<<k)+1][k]);}int sol(int l,int r,int v){    int la=l,lb=r;    while(lb-la>=1){        int mid=la+lb>>1;        if(rmq(la,mid)<=v)lb=mid;        else la=mid+1;    }    return la;}int main(){    int t;    scanf("%d",&t);    while(t--){        int n;        scanf("%d",&n);        for(int i=1;i<=n;i++){            scanf("%d",&a[i]);        }        ini(n);        int m;        scanf("%d",&m);        for(int i=0;i<m;i++){            int l,r;            scanf("%d%d",&l,&r);            int ans=a[l];            while(l<r){                int p=sol(l+1,r,ans);                ans%=a[p];                l=p;            }            printf("%d\n",ans);        }    }    return 0;}


0 0