「学习笔记」替罪羊树
「学习笔记」替罪羊树
其实早就会了……开一篇占个坑。
复杂度不会证,具体可见丽洁姐的论文。
模板
\(Code\ Below:\)
#include <bits/stdc++.h>
using namespace std;
const int maxn=100000+10;
const int inf=0x3f3f3f3f;
const double alpha=0.75;
int n,rt,sz,ch[maxn][2],fa[maxn],siz[maxn],val[maxn],sta[maxn],top;
inline bool balance(int x)
{
return 1.0*max(siz[ch[x][0]],siz[ch[x][1]])<alpha*siz[x];
}
inline void recycle(int x)
{
if(ch[x][0]) recycle(ch[x][0]);
sta[++top]=x;
if(ch[x][1]) recycle(ch[x][1]);
}
int build(int l,int r)
{
int mid=(l+r)>>1,x=sta[mid];
ch[x][0]=ch[x][1]=0;
if(l<mid) fa[ch[x][0]=build(l,mid-1)]=x;
if(mid<r) fa[ch[x][1]=build(mid+1,r)]=x;
siz[x]=siz[ch[x][0]]+siz[ch[x][1]]+1;
return x;
}
inline void rebuild(int x)
{
top=0;recycle(x);
int y=fa[x],k=(ch[y][1]==x),z=build(1,top);
ch[y][k]=z;fa[z]=y;
if(x==rt) rt=z;
}
inline void insert(int v)
{
if(!rt){rt=++sz;siz[rt]=1;val[rt]=v;return;}
int x=rt,y,k;
while(1)
{
siz[x]++;k=(val[x]<=v);y=x;x=ch[x][k];
if(!x){x=++sz;ch[y][k]=x;fa[x]=y;siz[x]=1;val[x]=v;break;}
}
y=0;
for(;x;x=fa[x])
if(!balance(x)) y=x;
if(y) rebuild(y);
}
inline void erase(int x)
{
if(ch[x][0]&&ch[x][1])
{
int y=ch[x][0];
while(ch[y][1]) y=ch[y][1];
val[x]=val[y];x=y;
}
int y=fa[x],k=(ch[y][1]==x),z=ch[x][0]?ch[x][0]:ch[x][1];
ch[y][k]=z;fa[z]=y;
for(;y;y=fa[y]) siz[y]--;
if(x==rt) rt=z;
}
inline int findid(int v)
{
int x=rt,k;
while(x)
{
if(val[x]==v) return x;
k=(val[x]<=v);x=ch[x][k];
}
return -1;
}
inline int findrnk(int v)
{
int x=rt,ans=0;
while(x)
{
if(val[x]>=v) x=ch[x][0];
else ans+=siz[ch[x][0]]+1,x=ch[x][1];
}
return ans+1;
}
inline int findkth(int k)
{
int x=rt;
while(x)
{
if(siz[ch[x][0]]>=k) x=ch[x][0];
else
{
k-=siz[ch[x][0]];
if(k==1) return val[x];
k--;x=ch[x][1];
}
}
return -1;
}
inline int findpre(int v)
{
int x=rt,ans=-inf;
while(x)
{
if(val[x]<v) ans=max(ans,val[x]),x=ch[x][1];
else x=ch[x][0];
}
return ans;
}
inline int findsuc(int v)
{
int x=rt,ans=inf;
while(x)
{
if(val[x]>v) ans=min(ans,val[x]),x=ch[x][0];
else x=ch[x][1];
}
return ans;
}
int main()
{
scanf("%d",&n);
int op,x;
while(n--)
{
scanf("%d%d",&op,&x);
if(op==1) insert(x);
if(op==2)
{
x=findid(x);
if(x>0) erase(x);
}
if(op==3) printf("%d\n",findrnk(x));
if(op==4) printf("%d\n",findkth(x));
if(op==5) printf("%d\n",findpre(x));
if(op==6) printf("%d\n",findsuc(x));
}
return 0;
}
没有人的算术
好题!
因为 \((x,y)\) 最多有 \(m\) 对,我们考虑用一个平衡树存下所有的二元组,然后 \(O(1)\) 查询 \(rank\)
具体的动态标号可以去看论文中 \(O(1)\) 查先后关系的算法。
最大值可以用线段树维护,时间复杂度 \(O(n\log n)\)
\(Code\ Below:\)
#include <bits/stdc++.h>
using namespace std;
const int maxn=500000+10;
const double alpha=0.75;
int n,m,pos[maxn];double a[maxn];
inline int read()
{
register int x=0,f=1;char ch=getchar();
while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
while(isdigit(ch)){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
return (f==1)?x:-x;
}
void print(int x)
{
if(x<0){putchar('-');x=-x;}
if(x>9) print(x/10);
putchar(x%10+'0');
}
struct data
{
int l,r;
data(int _l=0,int _r=0):l(_l),r(_r){}
};
inline bool operator < (const data &x,const data &y)
{
return a[x.l]<a[y.l]||(a[x.l]==a[y.l]&&a[x.r]<a[y.r]);
}
inline bool operator == (const data &x,const data &y)
{
return x.l==y.l&&x.r==y.r;
}
namespace SG
{
int rt,sz,R,ch[maxn][2],siz[maxn],sta[maxn],top;data val[maxn];
inline bool balance(int x)
{
return 1.0*max(siz[ch[x][0]],siz[ch[x][1]])<alpha*siz[x];
}
inline void recycle(int x)
{
if(ch[x][0]) recycle(ch[x][0]);
sta[++top]=x;
if(ch[x][1]) recycle(ch[x][1]);
}
int build(int l,int r,double _l,double _r)
{
int mid=(l+r)>>1,x=sta[mid];double mv=(_l+_r)/2;
ch[x][0]=ch[x][1]=0;a[x]=mv;
if(l<mid) ch[x][0]=build(l,mid-1,_l,mv);
if(mid<r) ch[x][1]=build(mid+1,r,mv,_r);
siz[x]=siz[ch[x][0]]+siz[ch[x][1]]+1;
return x;
}
inline void rebuild(int &x,double l,double r)
{
top=0;recycle(x);x=build(1,top,l,r);
}
inline int insert(int &x,double l,double r,data v)
{
double mid=(l+r)/2;int z;
if(!x){x=++sz;a[x]=mid;val[x]=v;siz[x]=1;return x;}
if(val[x]==v) return x;
else
{
siz[x]++;
if(val[x]<v) z=insert(ch[x][1],mid,r,v);
else z=insert(ch[x][0],l,mid,v);
}
if(balance(x))
{
if(R)
{
if(ch[x][0]==R) rebuild(ch[x][0],l,mid);
else rebuild(ch[x][1],mid,r);
R=0;
}
}
else R=x;
return z;
}
}
using SG::rt;
using SG::R;
namespace ST
{
#define lson (rt<<1)
#define rson (rt<<1|1)
int mx[maxn<<2];
inline int cmp(int x,int y)
{
return a[pos[x]]>=a[pos[y]]?x:y;
}
inline void pushup(int rt)
{
mx[rt]=cmp(mx[lson],mx[rson]);
}
void build(int l,int r,int rt)
{
if(l == r){mx[rt]=l;return;}
int mid=(l+r)>>1;
build(l,mid,lson);build(mid+1,r,rson);pushup(rt);
}
inline void update(int x,int l,int r,int rt)
{
if(l == r){mx[rt]=l;return;}
int mid=(l+r)>>1;
if(x <= mid) update(x,l,mid,lson);
else update(x,mid+1,r,rson);
pushup(rt);
}
int query(int L,int R,int l,int r,int rt)
{
if(L <= l && r <= R) return mx[rt];
int mid=(l+r)>>1;
if(L > mid) return query(L,R,mid+1,r,rson);
if(R <= mid) return query(L,R,l,mid,lson);
return cmp(query(L,R,l,mid,lson),query(L,R,mid+1,r,rson));
}
}
int main()
{
n=read(),m=read();
a[0]=-1;SG::insert(rt,0,1,data(0,0));
for(int i=1;i<=n;i++) pos[i]=1;
ST::build(1,n,1);
int l,r,k;char op;
while(m--)
{
op=getchar();
while(op!='C'&&op!='Q') op=getchar();
l=read(),r=read();
if(op=='C')
{
k=read();
pos[k]=SG::insert(rt,0,1,data(pos[l],pos[r]));
if(R) SG::rebuild(rt,0,1),R=0;
ST::update(k,1,n,1);
}
else print(ST::query(l,r,1,n,1)),putchar('\n');
}
return 0;
}
/*
5 10
C 1 1 1
C 2 1 2
Q 1 2
C 4 4 4
C 5 5 5
Q 4 5
Q 3 3
C 4 2 3
C 4 4 4
Q 3 4
*/
后缀平衡树改天再更啦~