#平衡樹#洛谷 1110 [ZJOI2007]報表統計
阿新 • • 發佈:2021-07-07
平衡樹
分析
最小值只需要開兩棵平衡樹,一棵維護所有元素,一棵維護相鄰最小值,
對於全域性最小值,對於每次插入查詢前驅後繼更新最小值即可,
相鄰最小值,對於每個原數列的數維護它的開頭和結尾是什麼數,
然後在往後插入一個數時直接先把原來的相鄰刪除再加進去,
求平衡樹的最小值即可
程式碼
#include <cstdio> #include <cctype> #include <cstring> #include <algorithm> #define rr register using namespace std; const int N=500011,inf=1e9; char str[21]; const double alp=0.75; int ans,n,m,len,St[N],Ed[N],a[N]; inline signed iut(){ rr int ans=0,f=1; rr char c=getchar(); while (!isdigit(c)) f=(c=='-')?-f:f,c=getchar(); while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar(); return ans*f; } inline void print(int ans){ if (ans<0) putchar('-'),ans=-ans; if (ans>9) print(ans/10); putchar(ans%10+48); } inline signed min(int a,int b){return a<b?a:b;} inline signed max(int a,int b){return a>b?a:b;} struct ScapeGoat_Tree{ int siz[N<<1],son[N<<1][2],root,tot=0,fat[N<<1],w[N<<1],stac[N<<1],TOP; inline void BUILD(){ tot=2,root=1; w[1]=-inf,siz[1]=2,son[1][1]=2, w[2]=inf,siz[2]=1,fat[2]=1; } inline bool balance(int x){return alp*siz[x]>=(max(siz[son[x][0]],siz[son[x][1]]));} inline void recycle(int x){ if (son[x][0]) recycle(son[x][0]); stac[++TOP]=x; if (son[x][1]) recycle(son[x][1]); } inline signed build(int l,int r){ if (l>r) return 0; rr 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; siz[x]=siz[son[x][0]]+siz[son[x][1]]+1; return x; } inline void rebuild(int x){ TOP=0; recycle(x); rr int fa=fat[x],wh=son[fat[x]][1]==x; rr int now=build(1,TOP); fat[son[fa][wh]=now]=fa; if (root==x) root=now; } inline void Insert(int x){ rr int now=root,renew=++tot; siz[renew]=1,w[renew]=x; while (1){ ++siz[now]; rr bool wh=x>=w[now]; if (son[now][wh]) now=son[now][wh]; else {fat[son[now][wh]=renew]=now; break;} } rr int UP=0; for (rr int i=renew;i;i=fat[i]) if (!balance(i)) UP=i; if (UP) rebuild(UP); } inline void Delete(int x){ if (son[x][0]&&son[x][1]){ rr int now=son[x][0]; while (son[now][1]) now=son[now][1]; w[x]=w[now],x=now; } rr int cho=son[x][0]?son[x][0]:son[x][1],wh=son[fat[x]][1]==x; fat[son[fat[x]][wh]=cho]=fat[x]; for (rr int i=fat[x];i;i=fat[i]) --siz[i]; if (x==root) root=cho; } inline signed arr(int x){ rr int now=root; while (1){ if (w[now]==x) return now; else now=son[now][w[now]<x]; } } inline signed rank(int x){ rr int now=root,ans=0; while (now){ if (x>w[now]) ans+=siz[son[now][0]]+1,now=son[now][1]; else now=son[now][0]; } return ans; } inline signed kth(int x){ rr int now=root; while (1){ if (siz[son[now][0]]==x-1) return now; else if (siz[son[now][0]]>=x) now=son[now][0]; else x-=siz[son[now][0]]+1,now=son[now][1]; } } inline signed pre(int x){ rr int now=root,ans=-inf; while (now){ if (x>w[now]) ans=max(ans,w[now]),now=son[now][1]; else now=son[now][0]; } return ans; } inline signed suf(int x){ rr int now=root,ans=inf; while (now){ if (x<w[now]) ans=min(ans,w[now]),now=son[now][0]; else now=son[now][1]; } return ans; } }Tre[2]; inline signed Abs(int x){return x<0?-x:x;} signed main(){ n=iut(),m=iut(),Tre[0].BUILD(),Tre[1].BUILD(); for (rr int i=1;i<=n;++i) St[i]=Ed[i]=a[i]=iut(); for (rr int i=1;i<n;++i) Tre[0].Insert(Abs(St[i+1]-St[i])); for (rr int i=1;i<=n;++i) Tre[1].Insert(St[i]); sort(a+1,a+1+n),ans=Abs(a[2]-a[1]); for (rr int i=3;i<=n;++i) ans=min(ans,Abs(a[i]-a[i-1])); for (rr int i=1;i<=m;++i){ scanf("%s",str+1),len=strlen(str+1); if (len==6){ rr int x=iut(),w=iut(); if (x<n) Tre[0].Delete(Tre[0].arr(Abs(St[x+1]-Ed[x]))); if (x<n) Tre[0].Insert(Abs(St[x+1]-w)); Tre[0].Insert(Abs(w-Ed[x])),Ed[x]=w; rr int t1=Tre[1].suf(-inf),t2=Tre[1].pre(inf); if (w<t1) ans=min(ans,t1-w); else if (t2<w) ans=min(ans,w-t2); else { if (Tre[1].suf(w-1)==w) {ans=0; continue;} ans=min(ans,min(w-Tre[1].pre(w),Tre[1].suf(w)-w)); } Tre[1].Insert(w); }else if (len==7) print(Tre[0].suf(-inf)),putchar(10); else print(ans),putchar(10); } return 0; }