【kd-tree】bzoj3489 A simple rmq problem

Orz zyf教给蒟蒻做法

  蒟蒻并不会这题正解……(可持久化树套树?。。。Orz

  对于每个点,我们可以求出pre[i],nex[i],那么询问的答案就是:求max (a[i]),其中 i 满足(pre[i]<ql and nex[i]>qr and i∈[ql,qr])

  然后我们以(i,pre[i],nex[i])为坐标……将所有点抽象到三维空间中,每次查询就相当于是一次区域求最值!

这题我的感受:

因为前面做了两道区域求和的……然后思路不由自主又代入到搞【子树最大值】来更新答案……然而忘记了单点更新,也就是:虽然这个子树不合法,但是这一个点(根)还是可能合法的……

然后就是:KD-Tree如果可以搞整个子树的话,那么用整个子树的最值去更新,会优化很多……?

终于1A了一道KD-Tree啦~好开心(虽然不是自己想出的做法……)

——http://www.cnblogs.com/Tunix/p/4522925.html

#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
#define N 100001
#define INF 2147483647
#define KD 3//ά¶ÈÊý
int qp[2];
int n,root,m;
int dn;
struct Node
{
    int minn[KD],maxx[KD],p[KD],w,maxv;
    int ch[2];
    void Init()
      {
        for(int i=0;i<KD;++i)
          minn[i]=maxx[i]=p[i];
        maxv=w;
      }
}T[N];
void Update(int rt)
{
    for(int i=0;i<2;++i)
      if(T[rt].ch[i])
        {
          T[rt].maxv=max(T[rt].maxv,T[T[rt].ch[i]].maxv);
          for(int j=0;j<KD;++j)
            {
              T[rt].minn[j]=min(T[rt].minn[j],T[T[rt].ch[i]].minn[j]);
              T[rt].maxx[j]=max(T[rt].maxx[j],T[T[rt].ch[i]].maxx[j]);
            }
        }
}
bool operator < (const Node &a,const Node &b){return a.p[dn]<b.p[dn];}
int Buildtree(int l=1,int r=n,int d=0)
{
    dn=d;
    int m=(l+r>>1);
    nth_element(T+l,T+m,T+r+1);
    T[m].Init();
    if(l!=m) T[m].ch[0]=Buildtree(l,m-1,(d+1)%KD);
    if(m!=r) T[m].ch[1]=Buildtree(m+1,r,(d+1)%KD);
    Update(m);
    return m;
}
int ans;
void Query(int rt=root)
{
    if(T[rt].p[0] < qp[0] &&
    T[rt].p[1] > qp[1] &&
    qp[0] <= T[rt].p[2]  && T[rt].p[2] <= qp[1])
      ans=max(ans,T[rt].w);
    for(int i=0;i<2;++i)
      if(T[rt].ch[i] &&
      T[T[rt].ch[i]].minn[0] < qp[0] &&
      T[T[rt].ch[i]].maxx[1] > qp[1] &&
      qp[0] <= T[T[rt].ch[i]].maxx[2] && T[T[rt].ch[i]].minn[2] <= qp[1])
        {
          if(T[T[rt].ch[i]].maxx[0] < qp[0] &&
          T[T[rt].ch[i]].minn[1] > qp[1] &&
          qp[0] <= T[T[rt].ch[i]].minn[2] && T[T[rt].ch[i]].maxx[2] <= qp[1])
            ans=max(ans,T[T[rt].ch[i]].maxv);
          else if(T[T[rt].ch[i]].maxv > ans)
            Query(T[rt].ch[i]);
        }
}
int nex[N],pre[N],now[N];
int main()
{
//  freopen("bzoj3489.in","r",stdin);
//  freopen("bzoj3489.out","w",stdout);
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;++i)
      scanf("%d",&T[i].w);
    for(int i=1;i<=n;++i)
      {
        pre[i]=now[T[i].w];
        now[T[i].w]=i;
      }
    for(int i=1;i<=n;++i)
      now[i]=n+1;
    for(int i=n;i;--i)
      {
        nex[i]=now[T[i].w];
        now[T[i].w]=i;
      }
    for(int i=1;i<=n;++i)
      {
        T[i].p[0]=pre[i];
        T[i].p[1]=nex[i];
        T[i].p[2]=i;
      }
    Buildtree();
    root=(1+n>>1);
    int x,y;
    for(;m;--m)
      {
        scanf("%d%d",&x,&y);
        qp[0]=min((x+ans)%n+1,(y+ans)%n+1);
        qp[1]=max((x+ans)%n+1,(y+ans)%n+1);
//        qp[0]=x;
//        qp[1]=y;
        ans=0;
        Query();
        printf("%d\n",ans);
      }
    return 0;
}
时间: 2024-09-29 10:28:40

【kd-tree】bzoj3489 A simple rmq problem的相关文章

[bzoj3489]A simple rmq problem

本题既不是rmq也不会simple(对我这种蒟蒻而言) 一开始只能想到树套树套树TAT然后看了看数据范围果断滚去膜拜题解. 然后才知道预先排序一下可以弄掉一个log.不过得写可持久化线段树套可持久化线段树.. 然后愉悦的开码了...感人的是竟然不用调...更感人的是交上去直接tle了. 然后从网上找了别人的代码(方法一样)发现同样的数据我要跑6s+..标称只要2s+.. 之后各种卡常还是慢了一倍TAT...最后自己写个max函数就和标程一样快了TAT这几天怎么总是出些奇怪的状况QAQ. 本来故事

bzoj3489: A simple rmq problem (主席树)

//========================== 蒟蒻Macaulish:http://www.cnblogs.com/Macaulish/  转载要声明! //========================== 说好的“因为是OJ上的题,就简单点好了.”呢? 一开始看不懂,不会写. 然后跪了一个晚上决定看云的题解&……似乎是主席树套主席树!吓傻,还开了40000000的数组.然后一交tle…… 然后p是不可能玩常数的. 找不到其他做法. 然后找到了神牛dwjshift,好心地提供了题

bzoj3489 A simple rmq problem 可持久化树套树

先预处理出两个个数组pre,next.pre[i]表示上一个与i位置数字相同的位置,若不存在则设为0:next[i]表示下一个与i位置数字相同的位置,若不存在则设为n+1.那么一个满足在区间[L,R]中只出现一次的数字,其pre[i]<L,next[i]>R. 这样我们可以先将pre进行排序,然后将pre可持久化,外层线段树套的是当前数字的位置i,内层线段树套的是next[i].外层线段树的节点总数是nlogn,内层线段树节点总数是nlogn^2.时间复杂度O(nlogn^2). 代码 1 #

【BZOJ3489】A simple rmq problem kd-tree

[BZOJ3489]A simple rmq problem Description 因为是OJ上的题,就简单点好了.给出一个长度为n的序列,给出M个询问:在[l,r]之间找到一个在这个区间里只出现过一次的数,并且要求找的这个数尽可能大.如果找不到这样的数,则直接输出0.我会采取一些措施强制在线. Input 第一行为两个整数N,M.M是询问数,N是序列的长度(N<=100000,M<=200000) 第二行为N个整数,描述这个序列{ai},其中所有1<=ai<=N 再下面M行,每

【BZOJ】【3489】A simple rmq problem

KD-Tree(乱搞) Orz zyf教给蒟蒻做法 蒟蒻并不会这题正解……(可持久化树套树?...Orz 对于每个点,我们可以求出pre[i],nex[i],那么询问的答案就是:求max (a[i]),其中 i 满足$ ( pre[i]<ql \ and \ nex[i]>qr\ and\ i \in [ql,qr] ) $ 然后我们以(i,pre[i],nex[i])为坐标……将所有点抽象到三维空间中,每次查询就相当于是一次区域求最值! 这题我的感受: 因为前面做了两道区域求和的……然后思路

【POJ 3368】 Frequent values(RMQ)

[POJ 3368] Frequent values(RMQ) Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 15813   Accepted: 5749 Description You are given a sequence of n integers a1 , a2 , ... , an in non-decreasing order. In addition to that, you are given seve

【CF 459D】 Pashmak and Parmida&#39;s problem

[CF 459D] Pashmak and Parmida's problem 预处理+线段树求逆序对 新学了树状数组 很适合这题 来一发 代码如下: #include <iostream> #include <cstdio> #include <cstdlib> #include <map> #include <cstring> #define ll long long using namespace std; map <int,int&

【BZOJ3669】[Noi2014]魔法森林【Link-Cut Tree】【最小生成树】

[题目链接] 一开始写了个二分a+最短路b,骗了65分,然后改成二分b+最短路a,骗了70分..发现二分是不对的之后,给答案取min,骗到了90分.出题人太不负责任了. 正解是枚举a,用LCT维护b的最小生成树. /* Telekinetic Forest Guard */ #include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int maxn = 500

【bzoj3489】 A simple rmq problem k-d树

由于某些原因,我先打了一个错误的树套树,后来打起了$k-d$.接着因不明原因在思路上被卡了很久,在今天中午蹲坑时恍然大悟...... 对于一个数字$a_i$,我们可以用一组三维坐标$(i,pre,nxt)$来表示,其中$i$表示该数字下标,$pre$表示在区间$[1,i)$中满足$a[j]=a[i]$的最大$j$,若不存在,则$pre=0$.$nxt$表示在区间$(i,n]$中满足$a[j]=a[i]$的最小$j$,若不存在,则$nxt=n+1$. 接着我们种一棵3-d树去存储这n个点.对于任意