CF765F Souvenirs

先把所有询问离线一下。
从右向左枚举左端点,线段树维护每一个右端点的答案。
(这里的每一个右端点包含的答案只包括以它为右端点的当前最小的差值)
因此对于询问l,r,应该查询线段树l,r的区间最小值。
每次左端点移动的时候,暴力的做法是直接for过去更新每一个位置。
考虑怎么优化。
先考虑更新比左端点的值大的位置。
首先向右找到第一个比它大的位置x,更新一下。
可以发现下一次的要更新的位置的值一定要属于[l,(l+r)/2]。
这要就只会向右边跳logn次。
每次找下一个合法位置用主席树实现。
更新比左端点的值小的位置的方法也同理。
总复杂度O(nlog^2)

#include<bits/stdc++.h>
#define N 330000
#define M 3300000
#define eps 1e-7
#define inf 1e9+7
#define db double
#define ll long long
#define ldb long double
using namespace std;
inline int read()
{
    char ch=0;
    int x=0,flag=1;
    while(!isdigit(ch)){ch=getchar();if(ch=='-')flag=-1;}
    while(isdigit(ch)){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
    return x*flag;
}
struct President_Tree
{
    #define lson lc[o]
    #define rson rc[o]
    #define mid ((l+r)>>1)
    int size,lc[M],rc[M],sumv[M];
    void pushup(int o){sumv[o]=sumv[lson]+sumv[rson];}
    void optset(int &o,int p,int l,int r,int q)
    {
        if(!o)o=++size;
        if(l==r){sumv[o]++;return;}
        if(q<=mid)optset(lson,lc[p],l,mid,q),rson=rc[p];
        else optset(rson,rc[p],mid+1,r,q),lson=lc[p];
        pushup(o);
    }
    int solve(int o,int p,int l,int r)
    {
        if(l==r)return l;
        if(sumv[lson]-sumv[lc[p]])return solve(lson,lc[p],l,mid);
        else return solve(rson,rc[p],mid+1,r);
    }
    int query(int o,int p,int l,int r,int ql,int qr)
    {
        if(ql>qr)return 0;
        if(ql<=l&&r<=qr)
        {
            if(sumv[o]-sumv[p])return solve(o,p,l,r);
            else return 0;
        }
        int ans=0;
        if(ql<=mid)ans=query(lson,lc[p],l,mid,ql,qr);if(ans)return ans;
        if(qr>mid)ans=query(rson,rc[p],mid+1,r,ql,qr);if(ans)return ans;
        return ans;
    }
    #undef lson 
    #undef rson
    #undef mid
}T;
struct Segment_Tree
{
    #define lson o<<1
    #define rson o<<1|1
    #define mid ((l+r)>>1)
    int minv[N*4];
    inline void pushup(int o){minv[o]=min(minv[lson],minv[rson]);}
    void build(int o,int l,int r)
    {
        minv[o]=+inf;if(l==r)return;
        build(lson,l,mid);build(rson,mid+1,r);
    }
    void optset(int o,int l,int r,int q,int k)
    {
        if(l==r){minv[o]=min(minv[o],k);return;}
        if(q<=mid)optset(lson,l,mid,q,k);
        else optset(rson,mid+1,r,q,k);
        pushup(o);
    }
    int query(int o,int l,int r,int ql,int qr)
    {
        if(ql<=l&&r<=qr)return minv[o];
        int ans=inf;
        if(ql<=mid)ans=min(ans,query(lson,l,mid,ql,qr));
        if(qr>mid)ans=min(ans,query(rson,mid+1,r,ql,qr));
        return ans;
    }
    #undef lson
    #undef rson
    #undef mid
}H;
int n,m,cnt,a[N],f[N],rt[N],ans[N];
bool cmp(int x,int y){return a[x]<a[y];};
struct node{int l,r,k;}p[N];
bool cmp_(node a,node b){return a.l>b.l;}
int get(int x)
{
    int l=0,r=n,mid;
    while(l<r)
    {
        mid=((l+r)>>1)+1;
        if(a[f[mid]]<=x)l=mid;else r=mid-1;
    }
    return rt[l];
}
int main()
{
    n=read();for(int i=1;i<=n;i++)a[i]=read(),f[i]=i;
    sort(f+1,f+n+1,cmp);
    for(int i=1;i<=n;i++)T.optset(rt[i],rt[i-1],1,n,f[i]);
    m=read();H.build(1,1,n);
    for(int i=1;i<=m;i++)p[i].l=read(),p[i].r=read(),p[i].k=i;sort(p+1,p+m+1,cmp_);
    for(int i=n,j=0;i>=1;i--)
    {
        int x,ql,qr,tt;
        x=i;ql=a[i];qr=+inf;tt=get(ql-1);
        while(x<n&&ql<=qr)
        {
            x=T.query(get(qr),tt,1,n,x+1,n);
            if(x==0)break;
            H.optset(1,1,n,x,abs(a[i]-a[x]));
            if(ql==qr)break;qr=(ql+a[x])/2;
        }
        x=i;ql=0;qr=a[i]-1;tt=get(qr);
        while(x<n&&ql<=qr)
        {
            x=T.query(tt,get(ql-1),1,n,x+1,n);
            if(x==0)break;
            H.optset(1,1,n,x,abs(a[i]-a[x]));
            if(ql==qr)break;ql=(a[x]+qr)/2;
        }
        while(j!=m&&p[j+1].l==i)j++,ans[p[j].k]=H.query(1,1,n,p[j].l,p[j].r);
    }
    for(int i=1;i<=m;i++)printf("%d\n",ans[i]);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/Creed-qwq/p/10513943.html