• [2020.11.13]CF765F Souvenirs


    题意

    给出一个长度为(n)的序列(a)(q)组询问,每次询问一个区间(l,r),求(|a_i-a_j|)的最小值,其中(i e j)(lle i,jle r)

    题解

    考虑离线,先考虑(i<j,a_ile a_j)的情况,然后把序列翻转考虑另一种情况。

    那么,我们枚举(j),考虑所有可能成为答案的(i),设为(i_1,i_2,dots,i_k),其中(i_i>i_2>i_3...>i_k),且(a_{i_1}<a_{i_2}<a_{i_3}<dots<a_{i_k})

    首先,(i_1)(j)前面第一个小于等于(a_j)的数。然后注意到如果(a_j-a_{i_x})要想成为答案必须要比(a_{i_x}-a_{i_{x-1}})要小,即(a_j-a_{i_x}<a_{i_x}-a_{i_{x-1}})变换得到(2(a_j-a_{i_x})<a_j-a_{i_{x-1}})

    这也就意味着(k)(O(log))级别的。使用主席树找到所有可能作为答案的((i,j))即可。

    然后就是从前往后枚举,树状数组维护后缀(min)得到答案。

    code:

    #include<bits/stdc++.h>
    #define ci const int&
    using namespace std;
    struct Query{
    	int p,*pos;
    };
    struct Val{
    	int v,*pos;
    }ar[100010];
    struct node{
    	int l,r,lc,rc,mx;
    }t[2000010];
    int n,Q,a[100010],rt[100010],cnt,ql[300010],qr[300010],prt[300010],num,mp[100010],tmp,bm[100010];
    vector<Query>qi[100010];
    void Build0(int&x,ci l,ci r){
    	x=++cnt,t[x].l=l,t[x].r=r,t[x].mx=0;
    	if(l==r)return(void)(t[x].lc=t[x].rc=0);
    	int mid=l+r>>1;
    	Build0(t[x].lc,l,mid),Build0(t[x].rc,mid+1,r);
    }
    void Build(ci lx,int&x,ci id,ci val){
    	if(t[lx].l>id||t[lx].r<id)return(void)(x=lx);
    	t[x=++cnt].l=t[lx].l,t[x].r=t[lx].r,t[x].mx=val;
    	if(t[x].l==t[x].r)return(void)(t[x].lc=t[x].rc=0);
    	Build(t[lx].lc,t[x].lc,id,val),Build(t[lx].rc,t[x].rc,id,val);
    }
    int Find(ci x,ci l,ci r){
    	if(r<t[x].l||t[x].r<l)return 0;
    	if(l<=t[x].l&&t[x].r<=r)return t[x].mx;
    	return max(Find(t[x].lc,l,r),Find(t[x].rc,l,r));
    }
    bool cmp(Val x,Val y){
    	return x.v<y.v;
    }
    void Ins(int x,ci v){
    	x=n-x+1;
    	while(x<=n)bm[x]=min(bm[x],v),x+=(x&-x);
    }
    int Que(int x){
    	x=n-x+1;
    	int ret=1e9;
    	while(x)ret=min(ret,bm[x]),x-=(x&-x);
    	return ret;
    }
    int Get(ci x){
    	int l=1,r=num,mid;
    	while(l<r)mid=l+r>>1,mp[mid]>=x?r=mid:l=mid+1;
    	return l;
    }
    void Solve(){
    	cnt=0,Build0(rt[0],1,num);
    	for(int i=1;i<=n;++i)Build(rt[i-1],rt[i],a[i],i),bm[i]=1e9;
    	for(int i=1;i<=n;++i){
    		tmp=Find(rt[i-1],1,a[i]);
    		while(tmp){
    			Ins(tmp,mp[a[i]]-mp[a[tmp]]);
    			if(a[i]==a[tmp])break;
    			tmp=Find(rt[tmp-1],Get(mp[a[i]]-(mp[a[i]]-mp[a[tmp]]-1>>1)),a[i]);
    		}
    		for(int j=0;j<qi[i].size();++j)(*qi[i][j].pos)=min(*qi[i][j].pos,Que(qi[i][j].p));
    	}
    }
    int main(){
    	scanf("%d",&n);
    	for(int i=1;i<=n;++i)scanf("%d",&ar[i].v),ar[i].pos=&a[i];
    	sort(ar+1,ar+n+1,cmp),ar[0].v=-1;
    	for(int i=1;i<=n;++i)num+=(ar[i].v!=ar[i-1].v),mp[num]=ar[i].v,(*ar[i].pos)=num;
    	scanf("%d",&Q);
    	for(int i=1;i<=Q;++i)scanf("%d%d",&ql[i],&qr[i]),prt[i]=1e9,qi[qr[i]].push_back((Query){ql[i],&prt[i]});
    	Solve();
    	for(int i=1;i<n-i+1;++i)swap(a[i],a[n-i+1]);
    	for(int i=1;i<=n;++i)vector<Query>().swap(qi[i]);
    	for(int i=1;i<=Q;++i)qi[n-ql[i]+1].push_back((Query){n-qr[i]+1,&prt[i]});
    	Solve();
    	for(int i=1;i<=Q;++i)printf("%d
    ",prt[i]);
    	return 0;
    }
    
  • 相关阅读:
    idea语法检查红线隐藏配置
    spring security
    linux centos7下安装fastdfs
    定时任务在多个服务实例之间最多只执行一次
    C++11:01auto关键字
    chap3 数组 #C
    django之模型层 各种查询 数据库查询优化相关 事务使用
    django orm 中表与表之间建关系 视图层 路由层 django请求生命周期
    django 静态文件的配置 orm 中 字段与数据的增删改查 使用MySQL数据库
    BOM,DOM, JS,JQ
  • 原文地址:https://www.cnblogs.com/xryjr233/p/CF765F.html
Copyright © 2020-2023  润新知