zoukankan      html  css  js  c++  java
  • bzoj 3489: A simple rmq problem

    Description

    给出一个长度为n的序列,给出M个询问:在[l,r]之间找到一个在这个区间里只出现过一次的数,并且要求找的这个数尽可能大。如果找不到这样的数,则直接输出0, 强制在线。

    Solution

    (pre[i]) 表示 (i) 之前第一个与 (a[i]) 相同的位置
    (nxt[i]) 表示 (i) 之后第一个与 (a[i]) 相同的位置
    满足要求的位置是:
    (l<=i<=r,pre[i]<l,nxt[i]>r)
    可以看成是点 ((i,pre,nxt))
    (kdtree) 维护一下包含所有点的区域就行了

    #include<bits/stdc++.h>
    using namespace std;
    template<class T>void gi(T &x){
    	int f;char c;
    	for(f=1,c=getchar();c<'0'||c>'9';c=getchar())if(c=='-')f=-1;
    	for(x=0;c<='9'&&c>='0';c=getchar())x=x*10+(c&15);x*=f;
    }
    const int N=1e5+10;
    int n,Q,nxt[N],pre[N],la[N],a[N],D,rt,ans=0;
    struct data{
    	int a[3],mx[3],mn[3],w,l,r,v;
    	inline int& operator [](int x){return a[x];}
    }t[N];
    inline bool operator <(data p,data q){return p[D]<q[D];}
    inline void upd(int o){
    	int l=t[o].l,r=t[o].r;
    	for(int i=0;i<3;i++)t[o].mn[i]=t[o].mx[i]=t[o][i];
    	for(int i=0;i<3;i++){
    		if(l)t[o].mn[i]=min(t[o].mn[i],t[l].mn[i]),
    				  t[o].mx[i]=max(t[o].mx[i],t[l].mx[i]);
    		if(r)t[o].mn[i]=min(t[o].mn[i],t[r].mn[i]),
    				  t[o].mx[i]=max(t[o].mx[i],t[r].mx[i]);
    	}
       t[o].v=max(t[o].w,max(t[l].v,t[r].v));
    }
    inline int build(int l,int r){
    	D=rand()%3;
    	int mid=(l+r)>>1,o=mid;
    	nth_element(t+l,t+mid,t+r+1);
    	if(l<mid)t[o].l=build(l,mid-1);
    	if(r>mid)t[o].r=build(mid+1,r);
    	return upd(o),o;
    }
    int l,r;
    inline bool check(int o){
    	if(t[o].mn[0]>r || t[o].mx[0]<l)return 0;
    	if(t[o].mn[1]>=l)return 0;
    	if(t[o].mx[2]<=r)return 0;
    	return 1;
    }
    inline void query(int o){
    	if(!o || !check(o))return ;
    	if(t[o].v<=ans)return ;
    	if(t[o][0]>=l && t[o][0]<=r && t[o][1]<l && t[o][2]>r)ans=max(ans,t[o].w);
    	query(t[o].l);query(t[o].r);
    }
    int main(){
    	freopen("pp.in","r",stdin);
    	freopen("pp.out","w",stdout);
    	srand(19260817);
    	cin>>n>>Q;
    	for(int i=1;i<=n;i++)gi(a[i]),pre[i]=la[a[i]],la[a[i]]=i;
    	memset(la,0,sizeof(la));
    	for(int i=n;i>=1;i--)nxt[i]=la[a[i]]?la[a[i]]:n+1,la[a[i]]=i;
    	for(int i=1;i<=n;i++)t[i][0]=i,t[i][1]=pre[i],t[i][2]=nxt[i],t[i].w=a[i];
    	rt=build(1,n);
    	int x,y;
    	while(Q--){
    		gi(x);gi(y);
    		l=(x+ans)%n+1;r=(y+ans)%n+1;if(l>r)swap(l,r);
    		ans=0;
    		query(rt);
    		printf("%d
    ",ans);
    	}
    	return 0;
    }
    
    
  • 相关阅读:
    JS Table排序类
    JavaScript使用技巧精萃
    修改鄒建 老師的SQL PivotTable,增加同分組非交叉欄位
    类似gmail添加附件
    [转贴]Js中 关于top、clientTop、scrollTop、offsetTop等
    Three Tier Code generation with Codesmith
    SQL中取得漢字拼音首字母或五筆首鍵編碼
    (转)ComputerStyle与currentStyle的区别
    html css样式色彩解析
    js 拖拽效果
  • 原文地址:https://www.cnblogs.com/Yuzao/p/9101196.html
Copyright © 2011-2022 走看看