Codeforces 765F. Souvenirs

每次询问一个区间内任意两个数差值绝对值的最小值

不妨考虑一个位置 i i ,他和哪些位置j(j<i)匹配可能更新区间的答案
这里只考虑 a[i]>a[j] a [ i ] > a [ j ] 的情况,另一种同理
可能贡献的 j j 一定是一个下降子,另外还有一个不那么显然的性质,就是真正有用的j序列的长度不超过 log w l o g   w ,因为假设(j,i)可以产生贡献,下一个贡献的位置是 j,j<j j ′ , j ′ < j ,那么真正有用的 j j ′ 需要满足两个条件 aiaj<aiaj,aiaj<ajaj a i − a j ′ < a i − a j , a i − a j ′ < a j ′ − a j ,否则 (j,j) ( j ′ , j ) 的贡献就优于 (j,i) ( j ′ , i )
那么可以发现, aiaj a i − a j 每次至少减一半,所以有用的 j j 不超过log个,我们可以直接找出这 log l o g j j <script id="MathJax-Element-16" type="math/tex">j</script>和i组成可能产生贡献的点对
然后每个询问在二维平面上就是询问一个矩形内最小的点这样的东西

code:

#include<set>
#include<map>
#include<deque>
#include<queue>
#include<stack>
#include<cmath>
#include<ctime>
#include<bitset>
#include<string>
#include<vector>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<climits>
#include<complex>
#include<iostream>
#include<algorithm>
#define ll long long
#define inf 1e9
using namespace std;

inline void down(int &a,const int &b){if(a>b)a=b;}
inline void read(int &x)
{
    char c; while(!((c=getchar())>='0'&&c<='9'));
    x=c-'0';
    while((c=getchar())>='0'&&c<='9') (x*=10)+=c-'0';
}
int ch[10],chn;
inline void Output(int x)
{
    if(!x) { puts("0");return; }
    while(x) ch[++chn]=x%10,x/=10;
    while(chn) putchar('0'+ch[chn--]);
    putchar('\n');
}
const int maxn = 210000;
const int maxm = 1100000;

int n,m;
int a[maxn];
struct ct{int x;int *i;}s[maxn];
inline bool cmp(const ct x,const ct y){return x.x<y.x;}
int To[maxn],id;
void Trans()
{
    for(int i=1;i<=n;i++) s[i].x=a[i],s[i].i=&a[i];
    sort(s+1,s+n+1,cmp);
    for(int i=1,la=s[1].x-1;i<=n;la=s[i].x,i++)
    {
        if(la!=s[i].x) To[++id]=s[i].x;
        (*s[i].i)=id;
    }
}

struct segment
{
    int mx[maxn<<2];
    void init() { memset(mx,-1,sizeof mx); }
    void pushup(int x) { mx[x]=max(mx[x<<1],mx[x<<1|1]); }
    int loc,c;
    void upd(int x,const int l,const int r)
    {
        if(l==r) { mx[x]=c;return; }
        int mid=(l+r)>>1;
        if(loc<=mid) upd(x<<1,l,mid);
        else upd(x<<1|1,mid+1,r);
        pushup(x);
    }
    int lx,rx;
    int querymx(int x,const int l,const int r)
    {
        if(!x||rx<l||r<lx) return -1;
        if(lx<=l&&r<=rx) return mx[x];
        int mid=(l+r)>>1;
        return max(querymx(x<<1,l,mid),querymx(x<<1|1,mid+1,r));
    }
}seg;

struct segment2
{
    int seg[maxn<<2];
    int loc,lx,rx,c;
    void init() { memset(seg,63,sizeof seg); }
    void upd(int x,const int l,const int r)
    {
        if(rx<l||r<lx) return;
        if(lx<=l&&r<=rx) { down(seg[x],c);return; }
        int mid=l+r>>1;
        upd(x<<1,l,mid); upd(x<<1|1,mid+1,r);
    }
    int query(int x,const int l,const int r,int c)
    {
        down(c,seg[x]);
        if(l==r) return c;
        int mid=l+r>>1;
        if(loc<=mid) return query(x<<1,l,mid,c);
        else return query(x<<1|1,mid+1,r,c);
    }
}seg2;

int op[maxm],ans[maxm];
vector<int>V[maxn];

int main()
{
    read(n);
    for(int i=1;i<=n;i++) read(a[i]); Trans();
    read(m);
    for(int i=1;i<=m;i++) 
    {
        int l,r; read(l); read(r);
        op[i]=l;
        V[r].push_back(i);
    }

    seg.init(); seg2.init();
    for(int i=1;i<=n;i++)
    {
        int las,l,r;

        las=0; r=1;
        while(1)
        {
            l=r,r=a[i];
            while(l<=r)
            {
                int mid=l+r>>1;
                if(To[mid]>=las) r=mid-1;
                else l=mid+1;
            }++r;
            seg.lx=r,seg.rx=a[i];
            int k=seg.querymx(1,1,n); if(k==-1) break;
            seg2.lx=1,seg2.rx=k,seg2.c=To[a[i]]-To[a[k]]; seg2.upd(1,1,n);
            if(las==To[a[i]]) break;
            las=To[a[k]]+(To[a[i]]-To[a[k]]+1)/2;
            if(las>To[a[i]]) break;
        }

        las=To[id]; l=id;
        while(1)
        {
            r=l,l=a[i];
            while(l<=r)
            {
                int mid=l+r>>1;
                if(To[mid]<=las) l=mid+1;
                else r=mid-1;
            }--l;
            seg.lx=a[i],seg.rx=l;
            int k=seg.querymx(1,1,n); if(k==-1) break;
            seg2.lx=1,seg2.rx=k,seg2.c=To[a[k]]-To[a[i]]; seg2.upd(1,1,n);
            if(las==To[a[i]]) break;
            las=To[a[k]]-(To[a[k]]-To[a[i]]+1)/2;
            if(las<To[a[i]]) break;
        }

        seg.loc=a[i],seg.c=i; seg.upd(1,1,n);

        for(int j=0;j<(int)V[i].size();j++)
        {
            int ii=V[i][j];
            seg2.loc=op[ii];
            ans[ii]=seg2.query(1,1,n,inf);
        }
    }
    for(int i=1;i<=m;i++) Output(ans[i]);

    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值