[CF765F]Souvenirs

[CF765F]Souvenirs

题目大意:

给定一个长度为\(n(n\le2\times10^5)\)的数列\(A_{1\sim n}\)\(m(m\le3\times10^5)\)次询问,每次询问区间\([l,r]\)内两个不相等的数之差的最小值。

思路:

将所有询问离线,按右端点排序。

枚举右端点\(r\),用线段树维护对于当前的右端点,每个左端点对应的答案。

线段树每个结点维护对应区间归并排序后的状态,即构造一棵归并树。

插入新的右端点就相当于在线段树对应区间找到最接近的数,然后更新答案。

显然暴力更新的复杂度在最坏情况下是单次\(\mathcal O(n)\)的。

发现由于右端点固定,若左边的答案已经不会比右边优,则左端点已经没有更新的必要。先更新右子区间,再更新左子区间剪枝即可。

时间复杂度\(\mathcal O(m\log^2 n)\)

源代码:

#include<cstdio>
#include<cctype>
#include<vector>
#include<climits>
#include<algorithm>
inline int getint() {
    register char ch;
    while(!isdigit(ch=getchar()));
    register int x=ch^'0';
    while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0');
    return x;
}
const int N=2e5+1,M=3e5;
int a[N],ans[M],min;
struct Query {
    int l,r,id;
    bool operator < (const Query &rhs) const {
        return r<rhs.r;
    }
};
Query q[M];
class SegmentTree {
    #define _left <<1
    #define _right <<1|1
    #define _par >>1
    #define mid ((b+e)>>1)
    private:
        int val[N<<2];
        std::vector<int> v[N<<2];
    public:
        void build(const int &p,const int &b,const int &e) {
            val[p]=INT_MAX;
            if(b==e) {
                v[p].push_back(a[b]);
                return;
            }
            build(p _left,b,mid);
            build(p _right,mid+1,e);
            v[p].resize(e-b+1);
            std::merge(v[p _left].begin(),v[p _left].end(),v[p _right].begin(),v[p _right].end(),v[p].begin());
        }
        void modify(const int &p,const int &b,const int &e,const int &r,const int &x) {
            if(r==e) {
                auto it=std::lower_bound(v[p].begin(),v[p].end(),x);
                if(it<v[p].end()) val[p]=std::min(val[p],std::abs(x-*it));
                if(--it>=v[p].begin()) val[p]=std::min(val[p],std::abs(x-*it));
                if(val[p]>=min) return;
                if(b==e) {
                    min=val[p];
                    return;
                }
            }
            if(r>mid) modify(p _right,mid+1,e,r,x);
            modify(p _left,b,mid,std::min(mid,r),x);
            val[p]=std::min(val[p _left],val[p _right]);
            min=std::min(min,val[p]);
        }
        int query(const int &p,const int &b,const int &e,const int &l,const int &r) const {
            if(b==l&&e==r) return val[p];
            int ret=INT_MAX;
            if(l<=mid) ret=std::min(ret,query(p _left,b,mid,l,std::min(mid,r)));
            if(r>mid) ret=std::min(ret,query(p _right,mid+1,e,std::max(mid+1,l),r));
            return ret;
        }
    #undef _left
    #undef _right
    #undef _par
    #undef mid
};
SegmentTree t;
int main() {
    const int n=getint();
    for(register int i=1;i<=n;i++) a[i]=getint();
    const int m=getint();
    for(register int i=0;i<m;i++) {
        const int l=getint(),r=getint();
        q[i]={l,r,i};
    }
    std::sort(&q[0],&q[m]);
    t.build(1,1,n);
    for(register int i=2,j=0;i<=n;i++) {
        min=INT_MAX;
        t.modify(1,1,n,i-1,a[i]);
        for(;j<m&&q[j].r==i;j++) {
            ans[q[j].id]=t.query(1,1,n,q[j].l,q[j].r-1);
        }
    }
    for(register int i=0;i<m;i++) {
        printf("%d\n",ans[i]);
    }
    return 0;
}   

猜你喜欢

转载自www.cnblogs.com/skylee03/p/9484014.html