【bzoj2770】YY的Treap

Description

志向远大的YY小朋友在学完快速排序之后决定学习平衡树,左思右想再加上SY的教唆,YY决定学习Treap。友爱教教父SY如砍瓜切菜般教会了YY小朋友Treap(一种平衡树,通过对每个节点随机分配一个priority,同时保证这棵平衡树关于priority是一个小根堆以保证效率)。这时候不怎么友爱的510跑了出来,他问了YY小朋友一个极不和谐的问题:怎么求Treap中两个点之间的路径长度。YY秒了之后决定把这个问题交给你来做,但只要求出树中两点的LCA。

Input

第一行两个整数n,m

第二行n个整数表示每个元素的key

第三行n个整数表示每个元素的priority

接下m行,每行一条命令

I A B,插入一个元素,key为A, priority为B

D A,删除一个元素,key为A

Q A B,询问key分别为A和B的LCA的key

Output

对于每个Q输出一个整数。

Sample Input

2 2
1 2
4 5
Q 1 2
I 3 3

Sample Output

1

HINT

数据保证n<=10^5,m<=3*10^5

其余整数均不超过long的范围

数据保证任意时刻树中key和priority均不相同

题解

首先询问的两个点的key是一个区间
则lca的key是在这个区间内pri最小的
那么就变成了维护一个集合
支持查询区间最值,加入删除元素
线段树/平衡树

超时代码(想练splay结果超时了)

#include<bits/stdc++.h>
#define inf 2147483647
#define N 400005
#define M 1000005
#define ll long long
using namespace std;
inline int read()
{
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
int c[N][2],fa[N],val[N],num[N],mn[N];
int n,m,tmp,cnt,rt,key[N],id[N];
void update(int x)
{
    mn[x]=val[x];id[x]=x;
    int l=c[x][0],r=c[x][1];
    if (l&&mn[l]<mn[x]) mn[x]=mn[l],id[x]=id[l];
    if (r&&mn[r]<mn[x]) mn[x]=mn[r],id[x]=id[r];
}
void rotate(int x,int &k)
{
    int y=fa[x],z=fa[y],l,r;
    if (c[y][0]==x) l=0;else l=1;r=l^1;
    if (y==k) k=x;
    else if (c[z][0]==y) c[z][0]=x;else c[z][1]=x;
    fa[x]=z;fa[y]=x;
    c[y][l]=c[x][r];fa[c[x][r]]=y;
    c[x][r]=y;
    update(y);update(x);
}
void splay(int x,int &k)
{
    int y,z;
    while (x!=k)
    {
        y=fa[x],z=fa[y];
        if (y!=k) if (c[z][0]==y^c[y][0]==x) rotate(x,k);else rotate(y,k);
        rotate(x,k);
    }
}
void insert(int &x,int k,int p,int f)
{
    if (x==0){x=++cnt;num[x]=k;fa[x]=f;val[x]=mn[x]=p;id[x]=x;splay(x,rt);return;}
    if (k>=num[x]) insert(c[x][1],k,p,x);
    else insert(c[x][0],k,p,x);
}
void find_before(int x,int k)
{
    if (x==0) return;
    if (num[x]<k) tmp=x,find_before(c[x][1],k);
    else find_before(c[x][0],k);
}
void find_after(int x,int k)
{
    if (x==0) return;
    if (num[x]>k) tmp=x,find_after(c[x][0],k);
    else find_after(c[x][1],k);
}
void del(int k)
{
    tmp=0;find_before(rt,k);
    int l=tmp;
    tmp=0;find_after(rt,k);
    int r=tmp;
    splay(l,rt);splay(r,c[rt][1]);
    c[r][0]=0;update(r);update(l);
}
int query(int a,int b)
{
    if (a>b) swap(a,b);
    tmp=0;find_before(rt,a);
    int l=tmp;
    tmp=0;find_after(rt,b);
    int r=tmp;
    splay(l,rt);splay(r,c[rt][1]);
    return num[id[c[r][0]]];
}
int main()
{
    n=read();m=read();
    insert(rt,-1,0,0);insert(rt,inf,0,0);
    for (int i=1;i<=n;i++) key[i]=read();
    for (int i=1;i<=n;i++)
    {
        int p=read();
        insert(rt,key[i],p,0);
    }
    while(m--)
    {
        char ch[5];
        scanf("%s",ch);
        if (ch[0]=='I')
        {
            int k=read(),p=read();
            insert(rt,k,p,0);
        }
        else if (ch[0]=='D')
        {
            int k=read();
            del(k);
        }
        else
        {
            int a=read(),b=read();
            printf("%d\n",query(a,b));
        }
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值