zoukankan      html  css  js  c++  java
  • [CF765F]Souvenirs

    [CF765F]Souvenirs

    题目大意:

    给定一个长度为(n(nle2 imes10^5))的数列(A_{1sim n})(m(mle3 imes10^5))次询问,每次询问区间([l,r])内两个不相等的数之差的最小值。

    思路:

    将所有询问离线,按右端点排序。

    枚举右端点(r),用线段树维护对于当前的右端点,每个左端点对应的答案。

    线段树每个结点维护对应区间归并排序后的状态,即构造一棵归并树。

    插入新的右端点就相当于在线段树对应区间找到最接近的数,然后更新答案。

    显然暴力更新的复杂度在最坏情况下是单次(mathcal O(n))的。

    发现由于右端点固定,若左边的答案已经不会比右边优,则左端点已经没有更新的必要。先更新右子区间,再更新左子区间剪枝即可。

    时间复杂度(mathcal O(mlog^2 n))

    源代码:

    #include<cstdio>
    #include<cctype>
    #include<vector>
    #include<climits>
    #include<algorithm>
    inline int getint() {
    	register char ch;
    	while(!isdigit(ch=getchar()));
    	register int x=ch^'0';
    	while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0');
    	return x;
    }
    const int N=2e5+1,M=3e5;
    int a[N],ans[M],min;
    struct Query {
    	int l,r,id;
    	bool operator < (const Query &rhs) const {
    		return r<rhs.r;
    	}
    };
    Query q[M];
    class SegmentTree {
    	#define _left <<1
    	#define _right <<1|1
    	#define _par >>1
    	#define mid ((b+e)>>1)
    	private:
    		int val[N<<2];
    		std::vector<int> v[N<<2];
    	public:
    		void build(const int &p,const int &b,const int &e) {
    			val[p]=INT_MAX;
    			if(b==e) {
    				v[p].push_back(a[b]);
    				return;
    			}
    			build(p _left,b,mid);
    			build(p _right,mid+1,e);
    			v[p].resize(e-b+1);
    			std::merge(v[p _left].begin(),v[p _left].end(),v[p _right].begin(),v[p _right].end(),v[p].begin());
    		}
    		void modify(const int &p,const int &b,const int &e,const int &r,const int &x) {
    			if(r==e) {
    				auto it=std::lower_bound(v[p].begin(),v[p].end(),x);
    				if(it<v[p].end()) val[p]=std::min(val[p],std::abs(x-*it));
    				if(--it>=v[p].begin()) val[p]=std::min(val[p],std::abs(x-*it));
    				if(val[p]>=min) return;
    				if(b==e) {
    					min=val[p];
    					return;
    				}
    			}
    			if(r>mid) modify(p _right,mid+1,e,r,x);
    			modify(p _left,b,mid,std::min(mid,r),x);
    			val[p]=std::min(val[p _left],val[p _right]);
    			min=std::min(min,val[p]);
    		}
    		int query(const int &p,const int &b,const int &e,const int &l,const int &r) const {
    			if(b==l&&e==r) return val[p];
    			int ret=INT_MAX;
    			if(l<=mid) ret=std::min(ret,query(p _left,b,mid,l,std::min(mid,r)));
    			if(r>mid) ret=std::min(ret,query(p _right,mid+1,e,std::max(mid+1,l),r));
    			return ret;
    		}
    	#undef _left
    	#undef _right
    	#undef _par
    	#undef mid
    };
    SegmentTree t;
    int main() {
    	const int n=getint();
    	for(register int i=1;i<=n;i++) a[i]=getint();
    	const int m=getint();
    	for(register int i=0;i<m;i++) {
    		const int l=getint(),r=getint();
    		q[i]={l,r,i};
    	}
    	std::sort(&q[0],&q[m]);
    	t.build(1,1,n);
    	for(register int i=2,j=0;i<=n;i++) {
    		min=INT_MAX;
    		t.modify(1,1,n,i-1,a[i]);
    		for(;j<m&&q[j].r==i;j++) {
    			ans[q[j].id]=t.query(1,1,n,q[j].l,q[j].r-1);
    		}
    	}
    	for(register int i=0;i<m;i++) {
    		printf("%d
    ",ans[i]);
    	}
    	return 0;
    }	
    
  • 相关阅读:
    C
    C
    如何收集项目日志统一发送到kafka中?
    Jmeter压测快速体验
    实时收集Storm日志到ELK集群
    Neo4j的查询语法笔记(二)
    Logstash2.3.4趟坑之集成Redis哨兵模式
    Spring-Boot中如何使用多线程处理任务
    使用SpringBoot1.4.0的一个坑
    手动从零使用ELK构建一套搜索服务
  • 原文地址:https://www.cnblogs.com/skylee03/p/9484014.html
Copyright © 2011-2022 走看看