码迷,mamicode.com
首页 > 其他好文 > 详细

[CF765F]Souvenirs

时间:2018-08-26 18:22:00      阅读:172      评论:0      收藏:0      [点我收藏+]

标签:force   code   inline   一段   维护   codeforce   lin   etc   方便   

codeforces

description

给你一个数列\(\{a_i\}\),每次询问一段区间\([l,r]\)内两数之差的最小值。
\(n\le10^5,m\le3\times10^5,a_i\le10^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(n\log n\log10^9+m\log 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\n",ans[i]);
    return 0;
}

[CF765F]Souvenirs

标签:force   code   inline   一段   维护   codeforce   lin   etc   方便   

原文地址:https://www.cnblogs.com/zhoushuyu/p/9537861.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!