【BZOJ3489】A simple rmq problem

原创 2016年04月24日 08:55:48

Description

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

Input

第一行为两个整数N,M。M是询问数,N是序列的长度(N<=100000,M<=200000)
第二行为N个整数,描述这个序列{ai},其中所有1<=ai<=N
再下面M行,每行两个整数x,y,
询问区间[l,r]由下列规则产生(OIER都知道是怎样的吧>_<):
l=min((x+lastans)mod n+1,(y+lastans)mod n+1);
r=max((x+lastans)mod n+1,(y+lastans)mod 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

HINT

注意出题人为了方便,input的第二行最后多了个空格。

2015.6.24新加数据一组,但未重测

Source

by zhzqkkk

因为在集中刷kdtree,正好从qiancl的kdtree系列整合里发现了这个题,然后就发现这题原来也可以不用树套树用kdtree做..
搞成三维kdtree,坐标分别代表 序列中位置,前一个和后一个相同数出现的位置,然后维护最大权值就行了

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#define MAXN 100010
#define GET (ch>='0'&&ch<='9')
#define MAXINT 0x3f3f3f3f
#define Dnum 3
using namespace std;
inline void in(int &x)
{
    char ch=getchar();x=0;
    while (!GET)    ch=getchar();
    while (GET) x=x*10+ch-'0',ch=getchar();
}
int n,m,cmp_d,ans,root;
int a,b,l,r;
int pre[MAXN],nxt[MAXN],lst[MAXN],w[MAXN];
struct KDtree
{
    int ch[2],d[Dnum],minn[Dnum],maxn[Dnum],val,maxv;
    inline void init()  {   for (int i=0;i<Dnum;++i)    minn[i]=maxn[i]=d[i];   }
    inline bool operator < (const KDtree& a)const   {   return d[cmp_d]<a.d[cmp_d]; }
}tree[MAXN];
inline void push_up(int rt)
{
    tree[rt].maxv=tree[rt].val;
    for (int i=0,x=0;i<2;++i)
        if ((x=tree[rt].ch[i]))
        {
            for (int j=0;j<Dnum;++j)
                tree[rt].minn[j]=min(tree[rt].minn[j],tree[x].minn[j]),
                tree[rt].maxn[j]=max(tree[rt].maxn[j],tree[x].maxn[j]);
            tree[rt].maxv=max(tree[rt].maxv,tree[x].maxv);
        }
}
int rebuild(int l=1,int r=n,int d=0)
{
    cmp_d=d;int mid=(l+r)>>1,nxtd=(d+1)%3;nth_element(tree+l,tree+mid,tree+r+1);
    tree[mid].init();
    if (l!=mid) tree[mid].ch[0]=rebuild(l,mid-1,nxtd);
    if (r!=mid) tree[mid].ch[1]=rebuild(mid+1,r,nxtd);
    return push_up(mid),mid;
}
inline bool check(int rt)
{
    if (tree[rt].maxn[1]<=r||tree[rt].minn[2]>=l||tree[rt].minn[0]>r||tree[rt].maxn[0]<l)   return 0;
    return 1;
}
void query(int rt=root)
{
    if (tree[rt].minn[0]>=l&&tree[rt].maxn[0]<=r&&tree[rt].minn[1]>r&&tree[rt].maxn[2]<l)   {   ans=max(ans,tree[rt].maxv);return;  }
    if (tree[rt].d[0]>=l&&tree[rt].d[0]<=r&&tree[rt].d[1]>r&&tree[rt].d[2]<l)   ans=max(ans,tree[rt].val);
    int ls=tree[rt].ch[0],rs=tree[rt].ch[1];
    if (tree[ls].maxv>tree[rs].maxv)
    {
        if (ls&&tree[ls].maxv>ans&&check(ls))   query(ls);
        if (rs&&tree[rs].maxv>ans&&check(rs))   query(rs);
    }
    else
    {
        if (rs&&tree[rs].maxv>ans&&check(rs))   query(rs);
        if (ls&&tree[ls].maxv>ans&&check(ls))   query(ls);
    }
}
int main()
{
    in(n);in(m);
    for (int i=1;i<=n;i++)  in(w[i]),pre[i]=lst[w[i]],lst[w[i]]=i;
    for (int i=1;i<=n;i++)  nxt[pre[i]]=i;nxt[0]=0;
    for (int i=1;i<=n;i++)
    {
        if (!nxt[i])    nxt[i]=n+1;
        tree[i].d[0]=i;tree[i].d[1]=nxt[i];tree[i].d[2]=pre[i];tree[i].val=w[i];
    }
    for (root=rebuild();m;m--)
    {
        in(a);in(b);l=min((a+ans)%n+1,(b+ans)%n+1);r=max((a+ans)%n+1,(b+ans)%n+1);
        ans=0;query();printf("%d\n",ans);
    }
}
版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/CreationAugust/article/details/51231983

BZOJ 3489 A simple rmq problem 可持久化树套树

题目大意:给定一个序列,多次询问某一区间中出现且仅出现一次的最大的数 令第i个数左侧第一个与这个数相同的数为last[i] 右侧第一个与这个相同的数为next[i] 那么一个数a[i]在区间内出现...
  • PoPoQQQ
  • PoPoQQQ
  • 2014-12-23 16:23:58
  • 3222

[BZOJ3489]A simple rmq problem(可持久化树套树||K-D tree)

还有一个月SDOI Round1
  • FromATP
  • FromATP
  • 2017-03-10 15:36:51
  • 504

[bzoj3489] A simple rmq problem 解题报告

说几种比较傻逼的做法: 考虑一个点i,设它前面第一个和它相等的点的位置是lastilast_i(若没有就是0),设它后面第一个和它相等的点的位置是nextinext_i(如果没有就是n+1),则它会...
  • TA201314
  • TA201314
  • 2016-04-26 07:11:39
  • 964

bzoj3489 -- 可持久化树套树

令lastilast_i表示aia_i前一个出现的位置(没出现过为00),nextinext_i表示aia_i后一个出现的位置(没出现过为n+1n+1)。 那么要满足的条件是:lastir,l≤i≤...
  • gjghfd
  • gjghfd
  • 2017-07-04 17:14:10
  • 200

BZOJ3489 A simple rmq problem

设第i个数上一次出现的位置为lst[i],下一次出现的位置为nxt[i],那么第i个数可以用作更新答案的条件就是lst[i]r&&l 把lst,nxt和i分别看作三维坐标,问题就转化为了立方体求最大...
  • neither_nor
  • neither_nor
  • 2016-07-09 23:26:34
  • 391

3489: A simple rmq problem

3489: A simple rmq problem Time Limit: 40 Sec  Memory Limit: 600 MB Submit: 1761  Solved: 592 [Su...
  • CRZbulabula
  • CRZbulabula
  • 2017-03-15 23:29:01
  • 241

BZOJ 3489 A simple rmq problem

3489: A simple rmq problem Time Limit: 10 Sec  Memory Limit: 512 MB Submit: 326  Solved: 85 [Submit]...
  • Gromah
  • Gromah
  • 2015-01-29 22:08:50
  • 1411

bzoj 3489: A simple rmq problem

what do you desire?
  • qq_20669971
  • qq_20669971
  • 2017-04-07 22:53:32
  • 438

【BZOJ3489】A simple rmq problem

Description因为是OJ上的题,就简单点好了。给出一个长度为n的序列,给出M个询问:在[l,r]之间找到一个在这个区间里只出现过一次的数,并且要求找的这个数尽可能大。如果找不到这样的数,则直接...
  • CreationAugust
  • CreationAugust
  • 2016-04-24 08:55:48
  • 1105
收藏助手
不良信息举报
您举报文章:【BZOJ3489】A simple rmq problem
举报原因:
原因补充:

(最多只允许输入30个字)