CF765F Souvenirs

考虑将询问离线,固定右端点 (i),这里只考虑满足 (j<i,a_j>a_i) 的答案,因为将 (a_i) 的值域翻转后再做一遍就能得到所有情况。询问就是查询对于每个位置 (j) 得到的答案的后缀最小值。

用权值线段树就能找到满足 (j<i,a_j>a_i) 的最大位置 (j),但一个一个往前跳找出所有的位置 (j),复杂度无法接受,还需进一步优化。

考虑当前位置为 (j),要想下一次找到的位置 (j') 能更新答案,其必须满足 (a_{j'}-a_i<a_j-a_{j'}),因为位置 (j') 更新过位置 (j),要更新后缀最小值就必须满足这个式子。移项得 (a_{j'}-a_i<frac{1}{2}(a_j-a_i)),发现差值每次减半,设值域为 (V),因此在限制下往前跳的合法位置个数为 (O(log V))。答案用树状数组维护后缀最小值即可。

复杂度为 (O(n log^2 V))

#include<bits/stdc++.h>
#define maxn 300010
#define maxm 10000010
#define all 1000000000
#define mid ((l+r)>>1)
#define lowbit(x) (x&(-x))
using namespace std;
template<typename T> inline void read(T &x)
{
    x=0;char c=getchar();bool flag=false;
    while(!isdigit(c)){if(c=='-')flag=true;c=getchar();}
    while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
    if(flag)x=-x;
}
int n,m,tot,root;
int a[maxn],ans[maxn],t[maxn],ls[maxm],rs[maxm],mx[maxm];
vector<pair<int,int> > ve[maxn];
void update(int x,int v)
{
    while(x) t[x]=min(t[x],v),x-=lowbit(x);
}
int ask(int x)
{
    int v=all;
    while(x<=n) v=min(v,t[x]),x+=lowbit(x);
    return v;
}
void modify(int l,int r,int pos,int v,int &cur)
{
    if(!cur) cur=++tot;
    mx[cur]=max(mx[cur],v);
    if(l==r) return;
    if(pos<=mid) modify(l,mid,pos,v,ls[cur]);
    else modify(mid+1,r,pos,v,rs[cur]);
}
int query(int L,int R,int l,int r,int cur)
{
    if(!cur) return 0;
    if(L<=l&&R>=r) return mx[cur];
    int v=0;
    if(L<=mid) v=max(v,query(L,R,l,mid,ls[cur]));
    if(R>mid) v=max(v,query(L,R,mid+1,r,rs[cur]));
    return v;
}
void clear()
{
    for(int i=1;i<=n;++i) t[i]=all;
    for(int i=1;i<=tot;++i) ls[i]=rs[i]=mx[i]=0;
    tot=root=0;
}
void work()
{
    clear();
    for(int i=1;i<=n;++i)
    {
        int pos=query(a[i],all,0,all,root);
        while(pos)
        {
            update(pos,a[pos]-a[i]);
            pos=query(a[i],(a[i]+a[pos])/2-(~(a[i]+a[pos])&1),0,all,root);
        }
        modify(0,all,a[i],i,root);
        for(int j=0;j<ve[i].size();++j)
            ans[ve[i][j].second]=min(ans[ve[i][j].second],ask(ve[i][j].first));
    }
}
int main()
{
    read(n);
    for(int i=1;i<=n;++i) read(a[i]);
    read(m);
    for(int i=1;i<=m;++i)
    {
        int l,r;
        read(l),read(r),ans[i]=all;
        ve[r].push_back({l,i});
    }
    work();
    for(int i=1;i<=n;++i) a[i]=all-a[i];
    work();
    for(int i=1;i<=m;++i) printf("%d
",ans[i]);
    return 0;
}
原文地址:https://www.cnblogs.com/lhm-/p/13795125.html