【BZOJ3489】A simple rmq problem(KD-Tree)

\(Description\)

因为是\(OJ\)上的题,就简单点好了。给出一个长度为\(n\)的序列,给出\(M\)个询问:在\([l,r]\)之间找到一个在这个区间里只出现过一次的数,并且要求找的这个数尽可能大。如果找不到这样的数,则直接输出\(0\)。我会采取一些措施强制在线。


\(Input\)

第一行为两个整数\(N,M\)。\(M\)是询问数,\(N\)是序列的长度\((N<=100000,M<=200000)\)

第二行为\(N\)个整数,描述这个序列{ai},其中所有\(1<=a_{i}<=N\)

再下面\(M\)行,每行两个整数\(x,y\),

询问区间\([l,r]\)由下列规则产生(\(OIER\)都知道是怎样的吧>_<):

\(l=min((x+lastans)\% n+1,(y+lastans)\% n+1);\)

\(r=max((x+lastans)\% n+1,(y+lastans)\% n+1);\)

\(Lastans\)表示上一个询问的答案,一开始\(lastans\)为\(0\)


\(Output\)

一共\(M\)行,每行给出每个询问的答案。


\(Sample\) \(Input\)

10 10
6 4 9 10 9 10 9 4 10 4
3 8
10 1
3 4
9 4
8 1
7 8
2 9
1 1
7 3
9 9


\(Sample\) \(Output\)

4
10
10
0
0
10
0
4
0
4


\(Source\)

 练习题 树9-2-树套树

思路

对于这道题,我们首先考虑如何处理 \(“\)[l,r]\(区间内只出现一次”\) 这个限制,我们两次循环处理出每个 \(i\) 位置 \(a_{i}\) 上次和下次出现的位置的 \(pre\) 和 \(nxt\) ,也就是说,对于这个数\(a_{i}\),只出现一次的区间是\([pre[a[i]],nxt[a[i]]]\)

于是,我们将每个位置 \(i\) 看成一个点 \((i,pre[i],nxt[i])\) ,这样,问题就转化为,求一个长方体中包含的点的最大值,这个问题我们用\(KD-Tree\)来解决

当然,你在做题过程中很大几率会碰到\(TLE\)的情况,遇到这种情况,你可以考虑:

  1. 各种卡常奇技淫巧
  2. 将结构体套结构体换为一个结构体
  3. 在\(KD-Tree\)查询时进行优化

详见丑陋的代码

\(p.s:\) 代码写太丑排版挂掉了,建议 \(ctrl+c\) 和 \(ctrl+v\) 到编译器上食用

#include<bits/stdc++.h>
using namespace std;
const int N=100010;
int n,m,nodetot=0,WD;
int a[N];
int pre[N],nxt[N];
int st[N];
struct point
{
    int x[3],val;
    bool operator <(const point & b) const
    {
        if(x[WD]==b.x[WD])
        {
            if(x[(WD+1)%3]==b.x[(WD+1)%3])return x[(WD+2)%3]<b.x[(WD+2)%3];
            return x[(WD+1)%3]<b.x[(WD+1)%3];
        }
        return x[WD]<b.x[WD];
    } 
}p[N];
struct tree
{
    int siz,lc,rc,maxn,maxx[3],minn[3];
    point pt;
}t[N];
inline void update(int k)
{
    t[k].siz=t[t[k].lc].siz+t[t[k].rc].siz+1;
    t[k].maxn=max(t[k].pt.val,max(t[t[k].lc].maxn,t[t[k].rc].maxn));
    for(int i=0;i<3;i++)
    {
        t[k].maxx[i]=t[k].minn[i]=t[k].pt.x[i];
        if(t[k].lc)
        {
            t[k].maxx[i]=max(t[k].maxx[i],t[t[k].lc].maxx[i]);
            t[k].minn[i]=min(t[k].minn[i],t[t[k].lc].minn[i]);
        }
        if(t[k].rc)
        {
            t[k].maxx[i]=max(t[k].maxx[i],t[t[k].rc].maxx[i]);
            t[k].minn[i]=min(t[k].minn[i],t[t[k].rc].minn[i]);
        }
    }
}
int build(int l,int r,int wd)
{
    if(l>r)return 0;
    int mid=(l+r)>>1,k=++nodetot;
    WD=wd;
    nth_element(p+l,p+mid,p+r+1);
    t[k].pt=p[mid];
    t[k].lc=build(l,mid-1,(wd+1)%3);
    t[k].rc=build(mid+1,r,(wd+1)%3);
    update(k);
    return k;
}

inline bool in(int l1,int r1,int l2,int r2,int l3,int r3,int mn1,int mx1,int mn2,int mx2,int mn3,int mx3)
{
    return mn1>=l1&&mx1<=r1&&mn2>=l2&&mx2<=r2&&mn3>=l3&&mx3<=r3;
}

inline bool out(int l1,int r1,int l2,int r2,int l3,int r3,int mn1,int mx1,int mn2,int mx2,int mn3,int mx3)
{
    return mn1>r1||mx1<l1||mn2>r2||mx2<l2||mn3>r3||mx3<l3;
}

int query(int l1,int r1,int l2,int r2,int l3,int r3,int k)
{
    if(in(l1,r1,l2,r2,l3,r3,t[k].minn[0],t[k].maxx[0],t[k].minn[1],t[k].maxx[1],t[k].minn[2],t[k].maxx[2]))return t[k].maxn;    
    int res=0;
    if(in(l1,r1,l2,r2,l3,r3,t[k].pt.x[0],t[k].pt.x[0],t[k].pt.x[1],t[k].pt.x[1],t[k].pt.x[2],t[k].pt.x[2]))res=t[k].pt.val;
    if(t[t[k].lc].maxn>t[t[k].rc].maxn)//就是这个优化
    {
        if(t[k].lc&&t[t[k].lc].maxn>res&&!out(l1,r1,l2,r2,l3,r3,t[t[k].lc].minn[0],t[t[k].lc].maxx[0],t[t[k].lc].minn[1],t[t[k].lc].maxx[1],t[t[k].lc].minn[2],t[t[k].lc].maxx[2]))res=max(res,query(l1,r1,l2,r2,l3,r3,t[k].lc));
        if(t[k].rc&&t[t[k].rc].maxn>res&&!out(l1,r1,l2,r2,l3,r3,t[t[k].rc].minn[0],t[t[k].rc].maxx[0],t[t[k].rc].minn[1],t[t[k].rc].maxx[1],t[t[k].rc].minn[2],t[t[k].rc].maxx[2]))res=max(res,query(l1,r1,l2,r2,l3,r3,t[k].rc));
    }
    else 
    {
        if(t[k].rc&&t[t[k].rc].maxn>res&&!out(l1,r1,l2,r2,l3,r3,t[t[k].rc].minn[0],t[t[k].rc].maxx[0],t[t[k].rc].minn[1],t[t[k].rc].maxx[1],t[t[k].rc].minn[2],t[t[k].rc].maxx[2]))res=max(res,query(l1,r1,l2,r2,l3,r3,t[k].rc));
        if(t[k].lc&&t[t[k].lc].maxn>res&&!out(l1,r1,l2,r2,l3,r3,t[t[k].lc].minn[0],t[t[k].lc].maxx[0],t[t[k].lc].minn[1],t[t[k].lc].maxx[1],t[t[k].lc].minn[2],t[t[k].lc].maxx[2]))res=max(res,query(l1,r1,l2,r2,l3,r3,t[k].lc));
    }
    return res;
}

inline int read()
{
    int x=0;
    char ch=getchar();
    while(!isdigit(ch))ch=getchar();
    while(isdigit(ch))
    {
        x=(x<<3)+(x<<1)+(ch^48);
        ch=getchar();
    }
    return x;
}

int main()
{
    n=read(),m=read();
    for(register int i=1;i<=n;i++)a[i]=read();
    for(register int i=1;i<=n;i++)
        pre[i]=st[a[i]],st[a[i]]=i;
    for(register int i=1;i<=n;i++)st[a[i]]=n+1;
    for(register int i=n;i>=1;i--)
        nxt[i]=st[a[i]],st[a[i]]=i;
    for(register int i=1;i<=n;i++)
        p[i].x[0]=i,p[i].x[1]=pre[i],p[i].x[2]=nxt[i],p[i].val=a[i];
    build(1,n,0);
    int lastans=0;
    int x,y,l,r;
    for(register int i=1;i<=m;i++)
    {
        x=read(),y=read();
        x=(x+lastans)%n,y=(y+lastans)%n;x++,y++;
        l=min(x,y),r=max(x,y);
        printf("%d\n",lastans=query(l,r,0,l-1,r+1,n+1,1));
    }
    return 0;
}
上一篇:第十二关——2012提高组真题


下一篇:3213