#替罪羊树,权值线段树,树套树,平衡树套线段树#洛谷 4278 带插入区间K小值
题目
带插入的 Dynamic Ranking,强制在线。
分析
由于插入导致下标发生改变,因此外层的树状数组应该替换为平衡树,每次对根到该点的路径上的权值线段树加一,
而旋转难以维护内层的线段树,因此使用替罪羊树直接拍扁重建,这里为了卡常去掉了垃圾回收而是使用定期重构,
当线段树结点数超过阈值就把整个替罪羊树拍扁重建,当然此时 \(\alpha\) 就得调大点,评论区给的是 \(0.955\),
还有什么递归转非递归之类的就不多说了,反正参数都很神秘就是了,唉。
代码
#include <cstdio>
#include <cctype>
#include <algorithm>
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<22,stdin)),p1==p2?EOF:*p1++)
using namespace std;
const int N=70001,M=24600000; char buf[1<<22],puf[1<<22],*p1,*p2; int nowp=-1;
const double alp=0.955; int n,a[N],rt[N],St[N],ToP,st[N],Top;
int iut(){
int ans=0; char c=getchar();
while (!isdigit(c)) c=getchar();
while (isdigit(c)) ans=ans*10+c-48,c=getchar();
return ans;
}
void Flush(){fwrite(puf,1,nowp+1,stdout),nowp=-1;}
void Putchar(char x){
if (nowp==(1<<22)) Flush();
puf[++nowp]=x;
}
void print(int ans){
char dig[10]; int len=-1;
do{
dig[++len]=ans%10+48,ans/=10;
}while (ans);
while (len>=0) Putchar(dig[len--]);
}
struct Segment_Tree{
int w[N<<10],cnt,TOP,ls[N<<10],rs[N<<10];
void update(int &rt,int l,int r,int x,int y){
if (!rt) rt=++cnt;
w[rt]+=y;
if (l==r) return;
int mid=(l+r)>>1;
if (x<=mid) update(ls[rt],l,mid,x,y);
else update(rs[rt],mid+1,r,x,y);
}
void Merge(int &fi,int se,int l,int r){
if (!fi&&!se) return;
int Fi=++cnt;
w[Fi]=w[fi]+w[se];
if (l==r){
fi=Fi;
return;
}
int mid=(l+r)>>1;
Merge(ls[Fi]=ls[fi],ls[se],l,mid);
Merge(rs[Fi]=rs[fi],rs[se],mid+1,r);
fi=Fi;
}
void recycle(int rt){
if (ls[rt]) recycle(ls[rt]);
if (rs[rt]) recycle(rs[rt]);
w[rt]=ls[rt]=rs[rt]=0;
}
}tre;
struct ScapeGoat_Tree{
int siz[N],son[N][2],root,tot=0,fat[N],stac[N],TOP;
bool balance(int x){return alp*siz[x]>=(max(siz[son[x][0]],siz[son[x][1]]));}
void recycle(int x){
if (son[x][0]) recycle(son[x][0]);
stac[++TOP]=x;
if (rt[x]) tre.recycle(rt[x]),rt[x]=0;
if (son[x][1]) recycle(son[x][1]);
}
int build(int l,int r){
if (l>r) return 0;
int mid=(l+r)>>1,x=stac[mid];
fat[son[x][0]=build(l,mid-1)]=x;
fat[son[x][1]=build(mid+1,r)]=x;
tre.Merge(rt[x]=rt[son[x][0]],rt[son[x][1]],0,N);
tre.update(rt[x],0,N,a[x],1);
siz[x]=siz[son[x][0]]+siz[son[x][1]]+1;
return x;
}
void rebuild(int x){
TOP=0; recycle(x);
int fa=fat[x],wh=son[fat[x]][1]==x;
int now=build(1,TOP);
fat[son[fa][wh]=now]=fa;
if (root==x) root=now;
}
void fetch(int kth,int y){
int now=root;
while (1){
if (kth<=siz[son[now][0]]) now=son[now][0];
else if (kth>siz[son[now][0]]+1) kth-=siz[son[now][0]]+1,now=son[now][1];
else break;
}
for (int i=now;i;i=fat[i]){
tre.update(rt[i],0,N,a[now],-1);
tre.update(rt[i],0,N,y,1);
}
a[now]=y;
}
void Insert(int kth){
int now=root,renew=++tot,wh;
while (1){
++siz[now];
tre.update(rt[now],0,N,a[tot],1);
if (kth>siz[son[now][0]]+1) kth-=siz[son[now][0]]+1,wh=1;
else wh=0;
if (son[now][wh]) now=son[now][wh];
else {fat[son[now][wh]=renew]=now; break;}
}
++siz[renew];
tre.update(rt[renew],0,N,a[tot],1);
int UP=0;
for (int i=renew;i;i=fat[i]) if (!balance(i)) UP=i;
if (UP) rebuild(UP);
}
void query(int now,int l,int r,int x,int y){
if (l==x&&r==y){
St[++ToP]=rt[now];
return;
}
int mid=l+siz[son[now][0]];
if (y<mid) query(son[now][0],l,mid-1,x,y);
else if (x>mid) query(son[now][1],mid+1,r,x,y);
else{
st[++Top]=a[now];
if (x<mid) query(son[now][0],l,mid-1,x,mid-1);
if (mid<y) query(son[now][1],mid+1,r,mid+1,y);
}
}
}Tre;
void Print(int now){
if (Tre.son[now][0]) Print(Tre.son[now][0]);
printf("%d ",a[now]);
if (Tre.son[now][1]) Print(Tre.son[now][1]);
}
int query(int x,int y,int kth){
int l=0,r=N; Top=ToP=0;
Tre.query(Tre.root,1,n,x,y);
while (l<r){
int mid=(l+r)>>1,sum=0;
for (int i=1;i<=ToP;++i) sum+=tre.w[tre.ls[St[i]]];
for (int i=1;i<=Top;++i) if (l<=st[i]&&st[i]<=mid) ++sum;
if (sum>=kth){
r=mid;
for (int i=1;i<=ToP;++i) St[i]=tre.ls[St[i]];
}else{
kth-=sum,l=mid+1;
for (int i=1;i<=ToP;++i) St[i]=tre.rs[St[i]];
}
}
return l;
}
int main(){
n=iut();
for (int i=1;i<=n;++i) a[i]=iut(),Tre.stac[i]=i;
Tre.root=Tre.build(1,Tre.tot=n);
for (int Q=iut(),lans=0;Q;--Q){
char ch=getchar();
while (!isalpha(ch)) ch=getchar();
int x=iut()^lans,y=iut()^lans;
switch (ch){
case 'Q':{
print(lans=query(x,y,iut()^lans));
Putchar(10);
break;
}
case 'M':{
Tre.fetch(x,y);
break;
}
case 'I':{
a[++n]=y;
Tre.Insert(x);
break;
}
}
if (tre.cnt>M) tre.cnt=0,Tre.rebuild(Tre.root);
}
Flush();
return 0;
}

浙公网安备 33010602011771号