3489: A simple rmq problem

写了两个版本:
一个树套树
一个kdt

树套树版本并不能在bz ac。
因为内存占用达到了可耻的700mb,即便加了优化依旧在600mb左右
考虑实际上就是要在给定的 [l,r] [ l , r ] 区间求出最大的数
使得 nxt[pos]<R   pre[pos]<L n x t [ p o s ] < R       p r e [ p o s ] < L
那么考虑预处理出每个点的 pre p r e nxt n x t
那么在插入第pos个版本时,更新 [L,pos] [ L , p o s ] 的值为 nxt n x t 即可
查询时寻找第 L L 这个点的最大值是否大于R
很遗憾会 mle m l e
c++代码如下:

#include<bits/stdc++.h>
#define rep(i,x,y) for(register int i = x ; i <= y; ++ i)
#define repd(i,x,y) for(register int i = x; i >= y; -- i)
using namespace std;
typedef long long ll;
template<typename T>inline bool chkmax(T&x,T y) { return x < y ? x = y,1:0; }
template<typename T>inline void read(T&x)
{
    char c ;int sign = 1;x = 0;
    do { c = getchar(); if(c == '-') sign = -1; }while(!isdigit(c));
    do { x = x * 10 + c - '0'; c = getchar(); }while(isdigit(c));
    x *= sign;
}

const int N = 1e5+500;
int rt[N],Ls[2000005],Rs[2000005];
int k[70000005],ls[70000005],rs[70000005],v[2000005];
int lst[N],p[N],q[N],a[N],lstans,sz,cnt,n,m;
int stk[500000],top;

bool add(int&rt,int y,int l,int r,int L,int R,int i)
{
    rt = top ? stk[top--] : ++ cnt;
    ls[rt] = ls[y]; rs[rt] = rs[y];
    k[rt] = k[y];
    if(k[rt] >= i)
    {
        stk[++top] = rt;
        rt = y;
        return true;
    }
    if(l == L && r == R) 
    {
        chkmax(k[rt],i);
        return false;
    }
    int mid = l + r >> 1;
    if(L > mid) 
    {
        if(add(rs[rt],rs[y],mid+1,r,L,R,i))
        {
            stk[++top] = rt;
            rt = y;
            return true;
        }return false;
    }
    else if( R <= mid) 
    {
        if(add(ls[rt],ls[y],l,mid,L,R,i))
        {
            stk[++top] = rt;
            rt = y;
            return true;
        }return false;
    }
    else 
    {
        bool e1 = add(ls[rt],ls[y],l,mid,L,mid,i);
        bool e2 = add(rs[rt],rs[y],mid+1,r,mid+1,R,i);
        if(e1 && e2)
        {
            stk[++top] = rt;
            rt = y;
            return true;
        }return false;
    }
}

void insert(int&rt,int y,int l,int r,int pos,int lst,int k,int w)
{
    rt = ++ sz;
    Ls[rt] = Ls[y];Rs[rt] = Rs[y];
    add(v[rt],v[y],1,n,lst,k,w);
    if(l == r) return ;
    int mid = l + r>> 1;
    if(pos <= mid) insert(Ls[rt],Ls[y],l,mid,pos,lst,k,w);
    else insert(Rs[rt],Rs[y],mid+1,r,pos,lst,k,w);
}

bool check(int rt,int l,int r,int pos,int w)
{
    if(k[rt] >= w) return true;
    if(l == r||!rt) return false;
    int mid = l + r >> 1;
    if(pos <= mid) return check(ls[rt],l,mid,pos,w);
    else return check(rs[rt],mid+1,r,pos,w);
}

int query(int x,int L,int R,int l,int r)
{
    if(l == r) return l;
    int mid = l + r >> 1;
    if(check(v[Rs[x]],1,n,L,R)  ) 
        return query(Rs[x],L,R,mid+1,r);
    else return query(Ls[x],L,R,l,mid);
}

int main()
{
    freopen("7.in","r",stdin);
    freopen("1.out","w",stdout);
    read(n); read(m);
    rep(i,1,n) read(a[i]);

    rep(i,1,n) lst[i] = n + 1;
    repd(i,n,1) p[i] = lst[a[i]],q[lst[a[i]]] = i,lst[a[i]] = i;

    rep(i,1,n)
    {
        insert(rt[i],rt[i-1],0,n,a[i],q[i] + 1,i,p[i] - 1);
    }

    int x,y;
    while(m -- )
    {
        read(x); read(y);
        x = (x+lstans)%n+1; y = (y+lstans)%n+1;
        if(x > y) swap(x,y);
        printf("%d\n",lstans = query(rt[y],x,y ,0,n));
    }
    return 0;
}

只能换算法了,树套树我是不想再改了…
考虑 kdt k d t
直接维护 nxt n x t pre p r e pos p o s 即可
一顿瞎搞直接 ac a c
c++代码如下:

#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <algorithm>
#define rep(i,x,y) for(register int i = x ; i <= y; ++ i)
#define repd(i,x,y) for(register int i = x; i >= y; -- i)
using namespace std;
typedef long long ll;
template<typename T>inline bool chkmax(T&x,T y) { return x < y ? x = y,1:0; }
template<typename T>inline bool chkmin(T&x,T y) { return x > y ? x = y,1:0; }
template<typename T>inline void read(T&x)
{
    char c ;int sign = 1;x = 0;
    do { c = getchar(); if(c == '-') sign = -1; }while(!isdigit(c));
    do { x = x * 10 + c - '0'; c = getchar(); }while(isdigit(c));
    x *= sign;
}

const int N = 1e5+50;
int n,m,k,a[N],lst[N];
struct DATA { int pre,nxt,pos; }p[N];

const bool cmp(DATA a,DATA b)
{
    if(k == 1) return a.pre < b.pre;
    if(k == 2) return a.nxt < b.nxt;
    if(k == 3) return a.pos < b.pos;
}

int ans,rt;

struct KD_TREE
{
    DATA w[N];
    int ls[N],rs[N];
    int L,R,sz,mx[N][4],mi[N][4],val[N];

    inline void pre() { memset(mi,0x3f,sizeof mi); }

    inline void update(int rt)
    {
        val[rt] = a[w[rt].pos];
        mi[rt][1] = w[rt].pre;
        mx[rt][2] = w[rt].nxt;
        mx[rt][3] = mi[rt][3] = w[rt].pos;
        if(rs[rt])
        {
            chkmax(val[rt],val[rs[rt]]);
            chkmax(mx[rt][2],mx[rs[rt]][2]);
            chkmax(mx[rt][3],mx[rs[rt]][3]);
            chkmin(mi[rt][1],mi[rs[rt]][1]);
            chkmin(mi[rt][3],mi[rs[rt]][3]);
        }
        if(ls[rt])
        {
            chkmax(val[rt],val[ls[rt]]);
            chkmax(mx[rt][2],mx[ls[rt]][2]);
            chkmax(mx[rt][3],mx[ls[rt]][3]);
            chkmin(mi[rt][1],mi[ls[rt]][1]);
            chkmin(mi[rt][3],mi[ls[rt]][3]);
        }
    }

    void build(int&rt,int l,int r)
    {
        int mid = l + r>>1;
        nth_element(p+l,p+mid,p+r+1,cmp);
        w[rt = ++sz] = p[mid];
        k = (k+1)%3+1;
        if(l < mid) build(ls[rt],l,mid-1);
        if(r > mid) build(rs[rt],mid+1,r);
        update(rt);
    }

    inline int find(int rt)
    {
        if(mi[rt][1] >= L || mx[rt][2] <= R || mi[rt][3] > R || mx[rt][3] < L) return -1;
        return val[rt];
    }

    void query(int rt)
    {
        if(w[rt].pre < L && w[rt].nxt > R && w[rt].pos <= R && w[rt].pos >= L)
            ans = max(ans,a[w[rt].pos]);

        int dl = find(ls[rt]);
        int dr = find(rs[rt]);
        if(dl < dr)
        {
            if(~dr && dr > ans) query(rs[rt]);
            if(~dl && dl > ans) query(ls[rt]);
        }
        else
        {
            if(~dl && dl > ans) query(ls[rt]);
            if(~dr && dr > ans) query(rs[rt]);
        }
    }
}kd;

int main()
{
    read(n); read(m);
    rep(i,1,n) read(a[i]);

    rep(i,1,n) lst[i] = n + 1;
    repd(i,n,1) 
    {
        p[i].nxt = lst[a[i]];
        p[lst[a[i]]].pre = i;
        p[i].pos = i;
        lst[a[i]] = i;
    }

    k = 1;
    kd.build(rt,1,n);

    while(m -- )
    {
        int x,y;
        read(x); read(y);
        x = (x+ans)%n+1; y = (y+ans)%n+1;
        if(x > y) swap(x,y);
        ans = 0; kd.L = x; kd.R = y;
        kd.query(rt);
        printf("%d\n",ans);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值