[CF765F]Souvenirs

Posted zhoushuyu

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[CF765F]Souvenirs相关的知识,希望对你有一定的参考价值。

codeforces

description

给你一个数列({a_i}),每次询问一段区间([l,r])内两数之差的最小值。
(nle10^5,mle3 imes10^5,a_ile10^9)

sol

首先询问离线,然后向右移动右端点,维护左端点的答案。为了方便,我们只考虑用(j<i,a_j>a_i)的点对去更新答案,剩下的可以把(a_i)的值域翻转然后再做一遍。
假设现在右端点在(i),我们先找到(max{j|a_j>a_i}),这样就可以用(a_j-a_i)更新左端点在([1,j])的答案。然后我们希望找一个(j'<j)满足(a_{j'}ge a_i)(a_{j'}-a_i<a_j-a_i),这样就可以进一步更新答案。接着可以令(j=j'),重复之间的操作,直至找不到一个满足条件的(j')为止。
但其实,这个限制条件可以进一步写为(a_{j'}-a_i<a_j-a_{j'})
很简单,因为在这之前(a_j-a_{j'})就已经更新过答案了,所以要想进一步更新除非答案更优。
移项可得(a_{j'}-a_i<frac 12(a_j-a_i))。发现每次(a_j)(a_i)的差至少减小一半,所以对于每一个(i),至多存在(O(log10^9))(j)可以更新答案。
那么复杂度就是(O(nlog nlog10^9+mlog n))
至于怎么找到(j'),我直接写的主席树。相当于是找满足值域在一定范围内的下标最大值。

code

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
using namespace std;
int gi(){
    int x=0,w=1;char ch=getchar();
    while ((ch<'0'||ch>'9')&&ch!='-') ch=getchar();
    if (ch=='-') w=0,ch=getchar();
    while (ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
    return w?x:-x;
}
const int N = 3e5+5;
const int inf = 1e9;
struct node{int l,r,id;}q[N];
struct seg{int ls,rs,v;}t[N*40];
int n,m,a[N],rt[N],tot,c[N],ans[N];
vector<int>v[N];
void mdf(int k,int v){while(k)c[k]=min(c[k],v),k^=k&-k;}
int qry(int k){int s=ans[0];while(k<=n)s=min(s,c[k]),k+=k&-k;return s;}
void modify(int &x,int l,int r,int p,int v){
    t[++tot]=t[x];x=tot;t[x].v=max(t[x].v,v);
    if (l==r) return;int mid=l+r>>1;
    if (p<=mid) modify(t[x].ls,l,mid,p,v);
    else modify(t[x].rs,mid+1,r,p,v);
}
int query(int x,int l,int r,int ql,int qr){
    if (ql>qr) return 0;
    if (!x||(l>=ql&&r<=qr)) return t[x].v;
    int mid=l+r>>1,s=0;
    if (ql<=mid) s=max(s,query(t[x].ls,l,mid,ql,qr));
    if (qr>mid) s=max(s,query(t[x].rs,mid+1,r,ql,qr));
    return s;
}
void work(){
    memset(c,63,sizeof(c));memset(rt,0,sizeof(rt));
    for (int i=1;i<=tot;++i) t[i]=(seg){0,0,0};tot=0;
    for (int i=1;i<=n;++i) modify(rt[i]=rt[i-1],0,inf,a[i],i);
    for (int i=1;i<=n;++i){
        int j=query(rt[i-1],0,inf,a[i],inf);
        while (j){
            mdf(j,a[j]-a[i]);
            j=query(rt[j-1],0,inf,a[i],(a[i]+a[j]>>1)-(~(a[i]+a[j])&1));
        }
        for (int j:v[i]) ans[q[j].id]=min(ans[q[j].id],qry(q[j].l));
    }
}
int main(){
    n=gi();
    for (int i=1;i<=n;++i) a[i]=gi();
    m=gi();
    for (int i=1;i<=m;++i) q[i]=(node){gi(),gi(),i};
    memset(ans,63,sizeof(ans));
    for (int i=1;i<=m;++i) v[q[i].r].push_back(i);
    work();
    for (int i=1;i<=n;++i) a[i]=inf-a[i];
    work();
    for (int i=1;i<=m;++i) printf("%d
",ans[i]);
    return 0;
}

以上是关于[CF765F]Souvenirs的主要内容,如果未能解决你的问题,请参考以下文章

codeforces 765F Souvenirs

codeforces765F Souvenirs

Codeforces 765F Souvenirs - 莫队算法 - 链表

Souvenirs CodeForces - 765F (线段树好题)

CF765FSouvenirs 主席树

cf765F.Souvenirs