zoukankan      html  css  js  c++  java
  • [bzoj3489]A simple rmq problem_KD-Tree

    A simple rmq problem

    题目大意:给定一个长度为$n$的序列,给出$m$个询问:在$[l,r]$之间找到一个在这个区间里只出现过一次的最大的数。

    注释:$1le nle 10^5$,$1le mle 2cdot 10^5$。


    想法

    我的第一想法是莫队。

    结果发现是强制在线(离线我也不会...

    想了想其实$KD-Tree$还是比较显然的。

    我们设$l_i$表示$a_i$上一次出现的位置,$r_i$表示下一次。

    紧接着我们把第$i$个数转化为三维坐标轴上的点$(l_i,i,r_i)$。

    用$KD-Tree$维护直接查即可。

    Code

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #define N 100010 
    using namespace std;
    int v[N],lst[N],dic[N],nxt[N],d,l,r,ans,rt;
    char *p1,*p2,buf[100000];
    #define nc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++)
    int rd() {int x=0,f=1; char c=nc(); while(c<48) {if(c=='-') f=-1; c=nc();} while(c>47) x=(((x<<2)+x)<<1)+(c^48),c=nc(); return x*f;}
    inline void Max(int &x,int y) {x=x>y?x:y;}
    inline void Min(int &x,int y) {x=x<y?x:y;}
    struct Node {int p[3],mx[3],mn[3],ans,size,val,ls,rs;}a[N];
    inline bool cmp(const Node &a,const Node &b)
    {
    	for(int i=0;i<3;i++) if(a.p[(d+i)%3]!=b.p[(d+i)%3]) return a.p[(d+i)%3]<b.p[(d+i)%3];
    	return true;
    }
    inline void pushup(int x,int k)
    {
    	a[x].size+=a[k].size;
    	for(int i=0;i<3;i++) Max(a[x].mx[i],a[k].mx[i]),Min(a[x].mn[i],a[k].mn[i]);
    	Max(a[x].ans,a[k].ans);
    }
    int build(int l,int r,int now)
    {
    	int mid=(l+r)>>1;
    	d=now; nth_element(a+l,a+mid,a+r+1,cmp);
    	for(int i=0;i<3;i++) a[mid].mx[i]=a[mid].mn[i]=a[mid].p[i];
    	a[mid].ans=a[mid].val;
    	if(l<mid) a[mid].ls=build(l,mid-1,(now+1)%3),pushup(mid,a[mid].ls);
    	if(mid<r) a[mid].rs=build(mid+1,r,(now+1)%3),pushup(mid,a[mid].rs);
    	return mid;
    }
    bool judge(int x)
    {
    	return a[x].ans>ans&&a[x].mx[0]>=l&&a[x].mn[0]<=r&&a[x].mn[1]<l&&a[x].mx[2]>r;
    }
    void query(int x)
    {
    	if(!x||!judge(x)) return;
    	if(a[x].p[0]>=l&&a[x].p[0]<=r&&a[x].p[1]<l&&a[x].p[2]>r) Max(ans,a[x].val);
    	query(a[x].ls); query(a[x].rs);
    }
    int main()
    {
    	int n=rd(),m=rd();
    	for(int i=1;i<=n;i++) v[i]=rd(),lst[i]=dic[v[i]],nxt[dic[v[i]]]=i,dic[v[i]]=i;
    	for(int i=1;i<=n;i++) a[i].p[0]=i,a[i].p[1]=lst[i],a[i].p[2]=nxt[i]?nxt[i]:n+1,a[i].val=v[i];
    	rt=build(1,n,0); while(m--)
    	{
    		l=(rd()+ans)%n+1,r=(rd()+ans)%n+1; if(l>r) swap(l,r);
    		ans=0,query(rt); printf("%d
    ",ans);
    	}
    	return 0;
    }
    

    小结:$KD-Tree$虽然是一个暴力,但是它的思想还是非常不错的。

  • 相关阅读:
    ZOJ 3795 Grouping
    ZOJ 3791 An Easy Game
    ZOJ 3790 Consecutive Blocks
    POJ 1451 T9
    POJ 1141 Brackets Sequence
    POJ 2411 Mondriaan's Dream
    POJ 2513 Colored Sticks
    Eclipse 快捷键大全
    C# lock关键字(多线程)
    C# 内部类
  • 原文地址:https://www.cnblogs.com/ShuraK/p/10243973.html
Copyright © 2011-2022 走看看