先讲讲重量平衡树是什么,可以先看2013年国家集训队clj的论文。
重量平衡树首先要保证平衡而且不能是均摊平衡,然后要么没有旋转,要么旋转是影响的子树大小要期望
log
log
或者均摊
log
log
。Treap和替罪羊树都满足重量平衡树的条件。
那么对于这题,发现复杂度瓶颈在于比较两个数的大小(复杂度可能达到指数级),因为操作中出现的数的种类是
O(n)
O
(
n
)
,我们希望能给每个数分配一个实数值来
O(1)
O
(
1
)
比较大小,这样就变成线段树裸题了。
考虑把数放在平衡树上,对于每棵子树,根节点分配的值为
mid
m
i
d
,左子树为
[l,mid)
[
l
,
m
i
d
)
,右子树为
(mid,r]
(
m
i
d
,
r
]
就可以了。那么首先要保证树不能太深(平衡),要不然精度不够,还有改变树的形态会导致子树中所有值重新计算,恰好符合重量平衡树的条件。
那么具体就是记
posi
p
o
s
i
表示第
i
i
<script type="math/tex" id="MathJax-Element-655">i</script>个数分配的值在平衡树上的位置,对于一个新合成的数,扔到平衡树上比较,如果没出现过就新建一个点,然后就是个线段树区间最大值了。
代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#include<queue>
#include<set>
#include<map>
#define ll long long
#define N 100010
using namespace std;
const double alpha=0.75;
const ll U=(1ll<<62)-1;
int n,m,top,tim;
int read()
{
int x=0,f=1;char ch=getchar();
for(;ch<'0'||ch>'9';ch=getchar()) if(ch=='-') f=-1;
for(;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0';
return x*f;
}
struct sctree;
struct node
{
sctree *l,*r;
};
sctree *NUL;
struct sctree
{
int sz,id;
node t;
ll lv,rv,mv;
sctree *ls,*rs;
sctree(){sz=0;lv=rv=0;ls=rs=NUL;}
sctree(node x,ll lx,ll rx)
{
t=x;sz=1;
lv=lx;rv=rx;mv=(lv+rv)>>1;
ls=rs=NUL;
}
void update()
{
sz=ls->sz+rs->sz+1;
}
bool isbad()
{
return (ls->sz>sz*alpha+5)||(rs->sz>sz*alpha+5);
}
}*sctr,*zero,*pos[N],*st[500010];
bool operator <(node p,node q)
{
if(p.l->mv==q.l->mv) return p.r->mv<q.r->mv;
return p.l->mv<q.l->mv;
}
bool operator ==(node p,node q)
{
return (p.l==q.l&&p.r==q.r);
}
void travel(sctree *p)
{
if(p==NUL) return ;
travel(p->ls);
st[++top]=p;
travel(p->rs);
}
sctree *divide(int l,int r,ll lx,ll rx)
{
if(l>r) return NUL;
int mid=(l+r)>>1;
sctree *p=st[mid];p->lv=lx;p->rv=rx;p->mv=(lx+rx)>>1;
p->ls=divide(l,mid-1,lx,p->mv);
p->rs=divide(mid+1,r,p->mv,rx);
p->update();
return p;
}
void rebuild(sctree *&p)
{
top=0;
travel(p);
p=divide(1,top,p->lv,p->rv);
}
sctree ** insert(sctree *&p,node v,ll lx,ll rx,int k)
{
if(p==NUL)
{
p=new sctree(v,lx,rx);
pos[k]=p;
return &NUL;
}
sctree **re;
p->sz++;
if(v<p->t) re=insert(p->ls,v,p->lv,p->mv,k);
else re=insert(p->rs,v,p->mv,p->rv,k);
if(p->isbad())re=&p;
return re;
}
void ins(node v,int k)
{
int re;
sctree ** p=insert(sctr,v,0,U,k);
if(*p!=NUL) rebuild(*p);
}
sctree *find(sctree *p,node v)
{
if(p==NUL||v==p->t) return p;
if(v<p->t) return find(p->ls,v);
else return find(p->rs,v);
}
struct segtree
{
int mx;
segtree *ls,*rs;
segtree(){ls=rs=0;}
void update()
{
if(pos[ls->mx]->mv>=pos[rs->mx]->mv) mx=ls->mx;
else mx=rs->mx;
}
void build(int l,int r)
{
if(l==r) {mx=l;return ;}
int mid=(l+r)>>1;
(ls=new segtree)->build(l,mid);
(rs=new segtree)->build(mid+1,r);
update();
}
void mdf(int l,int r,int x)
{
if(l==r) return ;
int mid=(l+r)>>1;
if(x<=mid) ls->mdf(l,mid,x);
else rs->mdf(mid+1,r,x);
update();
}
int qry(int l,int r,int lx,int rx)
{
if(l==lx&&r==rx) return mx;
int mid=(l+r>>1);
if(rx<=mid) return ls->qry(l,mid,lx,rx);
else if(lx>mid) return rs->qry(mid+1,r,lx,rx);
else
{
int lp=ls->qry(l,mid,lx,mid),rp=rs->qry(mid+1,r,mid+1,rx);
if(pos[lp]->mv>=pos[rp]->mv) return lp;
else return rp;
}
}
}*xtr;
int main()
{
n=read();m=read();
NUL=new sctree;NUL->ls=NUL->rs=NUL;sctr=NUL;
zero=new sctree;zero->mv=-1;
for(int i=1;i<=n;i++)
pos[i]=zero;
(xtr=new segtree)->build(1,n);
while(m--)
{
char opt;scanf("%s",&opt);
int l=read(),r=read(),k;
if(opt=='C')
{
k=read();
node v=(node){pos[l],pos[r]};
sctree *f=find(sctr,v);
if(f!=NUL) pos[k]=f;
else ins(v,k);
xtr->mdf(1,n,k);
}
else printf("%d\n",xtr->qry(1,n,l,r));
}
return 0;
}