zoukankan      html  css  js  c++  java
  • CF765F Souvenirs

    cf

    luogu

    没有强制在线,所以可以离线,把询问按右端点排序,然后从左往右枚举右端点,并维护左端点为(1)(i)的区间的答案,然后询问就可以直接取出来

    现在优化这个过程.因为是两个元素的最小绝对值,所以先考虑(i>j,a_ile a_j)的贡献,然后把序列和询问端点颠倒过来再做一遍,就能考虑所有情况.那么这个过程可以看成枚举到右端点(i),然后找到最大的(j<i)满足(a_ile a_j),更新左端点为(1)(j)的答案,然后继续,找最大的(j'<j)满足(a_ile a_{j'}<a_j),更新左端点为(1)(j')的答案...但是还是不优.进一步的,我们加一个限制,我们强制(a_j-a_{j'}ge a_{j'}-a_i),如果不满足这个条件,我们就让((j',j))这个点对去更新答案,并且不会更劣.这样子做,(a_j)(a_i)之差每做一次至少减少一半,所以找(j)的过程用上可持久化线段树,复杂度就是(O(nlognlog_{max a_i}))

    注意每次更新的都是一段前缀,所以可以把一个点答案改为后缀最小值,然后线段树单点修改区间查询即可

    #include<bits/stdc++.h>
    #define LL long long
    #define uLL unsigned long long
    #define db double
    
    using namespace std;
    const int N=3e5+10;
    int rd()
    {
    	int x=0,w=1;char ch=0;
    	while(ch<'0'||ch>'9'){if(ch=='-') w=-1;ch=getchar();}
    	while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}
    	return x*w;
    }
    int n,m,q;
    int s[N*50],ch[N*50][2],rt[N],tt;
    void inst(int o1,int o2,int x,int y)
    {
    	s[o1]=max(s[o2],y);
    	int l=1,r=m;
    	while(l<r)
    	{
    		int mid=(l+r)>>1;
    		if(x<=mid)
    		{
    			ch[o1][0]=++tt,ch[o1][1]=ch[o2][1];
    			o1=ch[o1][0],o2=ch[o2][0];
    			r=mid;
    		}
    		else
    		{
    			ch[o1][0]=ch[o2][0],ch[o1][1]=++tt;
    			o1=ch[o1][1],o2=ch[o2][1];
    			l=mid+1;
    		}
    		s[o1]=max(s[o2],y);
    	}
    }
    int quer(int o,int l,int r,int ll,int rr)
    {
    	if(!o||ll>rr) return 0;
    	if(ll<=l&&r<=rr) return s[o];
    	int an=0,mid=(l+r)>>1;
    	if(ll<=mid) an=max(an,quer(ch[o][0],l,mid,ll,rr));
    	if(rr>mid) an=max(an,quer(ch[o][1],mid+1,r,ll,rr));
    	return an;
    }
    int mi[N<<2];
    void psup(int o){mi[o]=min(mi[o<<1],mi[o<<1|1]);}
    void modif(int o,int l,int r,int lx,int x)
    {
    	if(l==r){mi[o]=min(mi[o],x);return;}
    	int mid=(l+r)>>1;
    	if(lx<=mid) modif(o<<1,l,mid,lx,x);
    	else modif(o<<1|1,mid+1,r,lx,x);
    	psup(o);
    }
    int q2(int o,int l,int r,int ll,int rr)
    {
    	if(ll<=l&&r<=rr) return mi[o];
    	int an=1<<30,mid=(l+r)>>1;
    	if(ll<=mid) an=min(an,q2(o<<1,l,mid,ll,rr));
    	if(rr>mid) an=min(an,q2(o<<1|1,mid+1,r,ll,rr));
    	return an;
    }
    int a[N],b[N],an[N];
    struct QR
    {
    	int l,r,i;
    	bool operator < (const QR &bb) const {return r<bb.r;}
    }qq[N];
    void wk()
    {
    	while(tt)
    	{
    		s[tt]=ch[tt][0]=ch[tt][1]=0;
    		--tt;
    	}
    	memset(mi,0x3f3f3f,sizeof(mi));
    	for(int i=1;i<=n;++i)
    		inst(rt[i]=++tt,rt[i-1],a[i],i);
    	for(int i=1,j=1;i<=n;++i)
    	{
    		int mx=1<<30,pp=i-1;
    		while(1)
    		{
    			int rr=upper_bound(b+1,b+m+1,mx)-b-1,k=quer(rt[pp],1,m,a[i],rr);
    			if(!k) break;
    			pp=k-1;
    			mx=b[a[k]];
    			modif(1,1,n,k,mx-b[a[i]]);
    			if(mx==b[a[i]]) break;
    			mx=(mx-b[a[i]]==1)?b[a[i]]:mx-(mx-b[a[i]])/2;
    		}
    		while(j<=q&&qq[j].r==i)
    		{
    			an[qq[j].i]=min(an[qq[j].i],q2(1,1,n,qq[j].l,qq[j].r));
    			++j;
    		}
    	}
    }
    
    int main()
    {
    	n=rd();
    	for(int i=1;i<=n;++i) a[i]=b[i]=rd();
    	sort(b+1,b+n+1),m=unique(b+1,b+n+1)-b-1;
    	b[++m]=1<<30|1;
    	for(int i=1;i<=n;++i) a[i]=lower_bound(b+1,b+m+1,a[i])-b;
    	q=rd();
    	for(int i=1;i<=q;++i)
    	{
    		an[i]=1<<30;
    		qq[i].l=rd(),qq[i].r=rd(),qq[i].i=i;
    	}
    	sort(qq+1,qq+q+1);
    	wk();
    	reverse(a+1,a+n+1);
    	for(int i=1;i<=q;++i)
    	{
    		qq[i].l=n-qq[i].l+1,qq[i].r=n-qq[i].r+1;
    		swap(qq[i].l,qq[i].r);
    	}
    	sort(qq+1,qq+q+1);
    	wk();
    	for(int i=1;i<=q;++i) printf("%d
    ",an[i]);
    	return 0; 
    }
    
    
  • 相关阅读:
    数据库学习笔记5---MySQL字符串函数、日期时间函数
    关于hibernate的AnnotationConfiguration的问题
    浅谈Java web 中request的setAttribute()用法
    JAVA常见面试题之Forward和Redirect的区别
    JSP页面中<%!%>与<%%>与<%=%>
    Servlet的生命周期
    JavaEE学习路线图
    java web项目WEB-INF与META-INF的作用
    iOS-申请邓白氏编码的超详细流程介绍
    从高版本JDK换成低版本JDK报错
  • 原文地址:https://www.cnblogs.com/smyjr/p/11530806.html
Copyright © 2011-2022 走看看