IT博客汇
  • 首页
  • 精华
  • 技术
  • 设计
  • 资讯
  • 扯淡
  • 权利声明
  • 登录 注册

    BZOJ2221:[Jsoi2009]面试的考验 单调性+随机数据

    wyfcyx发表于 2015-03-05 09:32:32
    love 0

    思路:

    宋文杰的题解很详细.

    一开始每个点30s,结果在OJ上一共30s...

    也就是说原来莫队是能过的,结果我无悬念TLE.

    莫队怎么做我就不说了.(貌似官方正解就是莫队...)

    莫队很暴力,因为没有利用一个题目中的性质:就是数据随机生成!

    询问随不随机意义是不大的.

    但是如果询问很特殊,我们就可以用科学的方法去处理:

    (1)任意两个区间不互相包含.这种情况我们将区间随便排个序就能发现总移动次数是\(O(n)\)的.

    (2)任意两个区间要么互相包含,要么不相交.这样就会形成一棵树.我们利用启发式合并,插入次数就为\(O(nlogn)\).

    但是随机数据显然没有这种性质.

    那么唯一可能有比较优秀的性质的就是随机数列了.

    考虑一种朴素算法:

    将所有询问离线按照右端点从小到大排序.

    从前向后依次加入右端点,令\(f_i\)表示当前以\(i\)为起点的后缀的答案,那么朴素来看,如果当前加入的是\(n\),那么\(f_1-f_{n-1}\)都需要更新.

    但是有很多冗余的更新.

    例如我们考虑所有大于\(a_n\)的数,不妨令\(a_i,a_j>a_n,a_i>a_j,i

    于是我们发现了某些单调性.

    我们利用数据结构维护后缀的答案,那么只需更新一些点就行了.

    那么我们的任务就是找到,对于\(n\)之前的数,一个均\(>a_n\)的递减序列,一个均\(

    然而由于是随机数据,序列中的元素个数是\(O(logn)\)级别的.

    这样总时间复杂度就是\(O(qlogn+nlog^2n)\).

    具体去看宋文杰的题解.

    (另外此题要求结果\(>0\) 23333)

    #include
    #include
    #include
    #include
    #include
    using namespace std;
    
    #define N 100010
    #define Q 100010
    int n,q,a[N];
    
    struct Interval{
    	int l,r,lab;
    	bool operator<(const Interval&B;)const{return ry)x=y;}
    struct SegmentTree{
    	int A[262144],M;
    	inline void Init(int _siz){
    		for(M=1;M<(_siz+2);M<<=1);
    		memset(A,0x3f,sizeof A);
    	}
    	inline void modify(int x,int d){
    		for(x+=M;x;x>>=1)mini(A[x],d);
    	}
    	inline int query(int tl,int tr){
    		int re=~0U>>1;
    		for(tl+=M-1,tr+=M+1;tl^tr^1;tl>>=1,tr>>=1){
    			if(~tl&1)mini(re,A[tl^1]);
    			if(tr&1)mini(re,A[tr^1]);
    		}
    		return re;
    	}
    }Seg;
    
    int preless[N],premore[N],small[N][30],big[N][30],stk[N],top;
    
    int main(){
    	//freopen("tt.in","r",stdin);
    	scanf("%d%d",&n;,&q;);
    	register int i,j,k;
    	
    	for(i=1;i<=n;++i)scanf("%d",&a;[i]);
    	
    	for(i=1;i<=q;++i)
    		scanf("%d%d",&S;[i].l,&S;[i].r),S[i].lab=i;
    	sort(S+1,S+q+1);
    	
    	Seg.Init(n);
    	
    	for(i=1;i<=n;++i){
    		while(top&&a;[stk[top]]>=a[i])--top;
    		preless[i]=stk[top];
    		stk[++top]=i;
    	}
    	top=0;
    	for(i=1;i<=n;++i){
    		while(top&&a;[stk[top]]<=a[i])--top;
    		premore[i]=stk[top];
    		stk[++top]=i;
    	}
    	
    	for(i=1;i<=n;++i){
    		if(premore[i]){
    			big[i][++big[i][0]]=premore[i];
    			j=big[i][1];
    			while(1){
    				bool find=0;
    				for(k=1;k<=small[j][0];++k)if(a[small[j][k]]>a[i]){find=1;break;}
    				if(find)big[i][++big[i][0]]=(j=small[j][k]);else break;
    			}
    		}
    		if(preless[i]){
    			small[i][++small[i][0]]=preless[i];
    			j=small[i][1];
    			while(1){
    				bool find=0;
    				for(k=1;k<=big[j][0];++k)if(a[big[j][k]]<=n;++i){
    		for(k=1;k<=small[i][0];++k)Seg.modify(small[i][k],a[i]-a[small[i][k]]);
    		for(k=1;k<=big[i][0];++k)Seg.modify(big[i][k],a[big[i][k]]-a[i]);
    		
    		for(;j<=q&&S;[j].r==i;++j)re[S[j].lab]=Seg.query(S[j].l,S[j].r);
    		
    	}
    	
    	for(i=1;i<=q;++i)printf("%d\n",re[i]);
    	
    	return 0;
    }


沪ICP备19023445号-2号
友情链接