zoukankan      html  css  js  c++  java
  • [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;
    }
    
  • 相关阅读:
    HDU 4122 Alice's mooncake shop
    win7 Visual Studio 2008 安装程序时出现“ 加载安装组件时遇到问题。取消安装。”处理方法
    [置顶] 《程序员,你伤不起》–读书笔记-序
    顺序查找的优化方法
    结构体的大小的计算与空间的优化--之基本类型
    poj 1836 Alignment
    HDU 4721 Food and Productivity (二分+树状数组)
    POJ 1724 最短路费用限制
    Java面试题之九
    Eclipse 支持jQuery 自动提示
  • 原文地址:https://www.cnblogs.com/zhoushuyu/p/9537861.html
Copyright © 2011-2022 走看看