zoukankan      html  css  js  c++  java
  • 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;
    }
    
  • 相关阅读:
    RHEL 5.7 Yum配置本地源[Errno 2] No such file or directory
    SQL SERVER中什么情况会导致索引查找变成索引扫描
    Vmware扩展磁盘如何不需重启系统
    Vmware虚拟机进入BIOS方法
    Linux LVM学习总结——删除物理卷
    Linux系统检查查看桌面环境
    spring面试问题与答案集锦
    solr查询特殊字符的处理
    阅读源代码的一点小技巧
    solr查询工作原理深入内幕
  • 原文地址:https://www.cnblogs.com/lhm-/p/13795125.html
Copyright © 2011-2022 走看看