#替罪羊树,线段树#洛谷 6272 [湖北省队互测2014] 没有人的算术
分析
其实抛开 \(a[k]\) 的类型不谈,外层相当于是线段树的单点修改和区间查询。
主要是比较大小的问题,不妨用一棵平衡树维护偏序关系,用一个数对维护,
数对的每一个值对应了一个赋值,赋值由平衡树的划分决定,
但是如果树高过高就会影响精度,而旋转难以维护赋值,所以需要替罪羊树直接拍扁重建。
代码
#include <cstdio>
#include <cctype>
#include <algorithm>
using namespace std;
const int N=600011;
const double alp=0.75;
int n,Q,w[N],a[N]; double b[N];
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;
}
inline void print(int ans){
if (ans>9) print(ans/10);
putchar(ans%10+48);
}
bool chose(pair<int,int>wl,pair<int,int>wr){return b[wl.first]==b[wr.first]?b[wl.second]>=b[wr.second]:b[wl.first]>b[wr.first];}
struct ScapeGoat_Tree{
int siz[N],son[N][2],root,tot=0,fat[N],stac[N],TOP; pair<int,int>w[N];
void BUILD(){siz[1]=root=tot=1,w[1]=make_pair(0,0),b[1]=165;}
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 (son[x][1]) recycle(son[x][1]);
}
int build(int l,int r,double L,double R){
if (l>r) return 0;
int mid=(l+r)>>1,x=stac[mid];
double MID=(L+R)/2; b[x]=MID;
fat[son[x][0]=build(l,mid-1,L,MID)]=x;
fat[son[x][1]=build(mid+1,r,MID,R)]=x;
siz[x]=siz[son[x][0]]+siz[son[x][1]]+1;
return x;
}
void rebuild(int x,double L,double R){
TOP=0; recycle(x);
int fa=fat[x],wh=son[fat[x]][1]==x;
int now=build(1,TOP,L,R);
fat[son[fa][wh]=now]=fa;
if (root==x) root=now;
}
int Insert(pair<int,int>x){
double L=0,R=330;
int now=root;
while (1){
if (b[w[now].first]==b[x.first]&&b[w[now].second]==b[x.second]) return now;
bool wh=chose(x,w[now]);
if (wh) L=(L+R)/2;
else R=(L+R)/2;
if (!son[now][wh]){
fat[son[now][wh]=++tot]=now;
w[tot]=x,b[tot]=(L+R)/2;
break;
}else now=son[now][wh];
}
for (int i=tot;i;i=fat[i]) ++siz[i];
int UP=0; double UPL=-1,UPR=-1;
for (int i=tot;i;i=fat[i]){
if (!balance(i)) UP=i,UPL=L,UPR=R;
if (son[fat[i]][1]==i) L=L*2-R;
else R=R*2-L;
}
if (UP) rebuild(UP,UPL,UPR);
return tot;
}
}Tre;
int pup(int wl,int wr){return chose(Tre.w[a[wl]],Tre.w[a[wr]])?wl:wr;}
void build(int k,int l,int r){
if (l==r){
w[k]=l;
return;
}
int mid=(l+r)>>1;
build(k<<1,l,mid);
build(k<<1|1,mid+1,r);
w[k]=pup(w[k<<1],w[k<<1|1]);
}
void update(int k,int l,int r,int x){
if (l==r){
w[k]=x;
return;
}
int mid=(l+r)>>1;
if (x<=mid) update(k<<1,l,mid,x);
else update(k<<1|1,mid+1,r,x);
w[k]=pup(w[k<<1],w[k<<1|1]);
}
int query(int k,int l,int r,int x,int y){
if (l==x&&r==y) return w[k];
int mid=(l+r)>>1;
if (y<=mid) return query(k<<1,l,mid,x,y);
else if (x>mid) return query(k<<1|1,mid+1,r,x,y);
else{
int wl=query(k<<1,l,mid,x,mid),wr=query(k<<1|1,mid+1,r,mid+1,y);
return pup(wl,wr);
}
}
int main(){
n=iut(),Q=iut(),b[0]=-1,Tre.BUILD();
for (int i=1;i<=n;++i) a[i]=1;
build(1,1,n);
for (int i=1;i<=Q;++i){
char ch=getchar();
while (!isalpha(ch)) ch=getchar();
int x=iut(),y=iut();
if (ch=='C'){
int z=iut();
a[z]=Tre.Insert(make_pair(a[x],a[y]));
update(1,1,n,z);
}else print(query(1,1,n,x,y)),putchar(10);
}
return 0;
}

浙公网安备 33010602011771号