UOJ#55. 【WC2014】紫荆花之恋 点分树 替罪羊树 平衡树 splay Treap
作者:互联网
原文链接https://www.cnblogs.com/zhouzhendong/p/UOJ55.html
题解
做法还是挺容易想到的。
但是写的话……
首先这种题如果只要求一棵树中的满足条件的点数(不需要在加点的同时维护答案),那么显然可以点分治:
假设当前点分中心为 x,设点 y 与 x 的距离为 d[y] ,然后,我们把 $d[a] + d[b] \leq r[a] + r[b]$ 移一下项,得到:
$$d[a]-r[a]\leq r[b] - d[b]$$
那么,我们只需要对于每一个点 b 求出与它不在 x 的同一个子树的节点 a 的个数,a 要满足 $d[a]-r[a]\leq r[b]-d[b]$ 。这个东西显然是可以用数据结构维护的。
具体用什么呢?
再说。
现在我们要动态维护答案。考虑如果可以离线怎么做:
对最终的树建一个点分树,也就是搞一个动态点分治。对于每一个点分中心,维护他控制的区域内所有节点的 d[a]-r[a] ;对于他的每一个子树,也维护一下这个东西。
那么加入一个点的时候,我们只要在点分树上走一趟,通过维护的信息更新答案的同时加入当前节点的贡献。
所以我们要的数据结构得支持插入和询问排名,那么自然选用平衡树。
所以离线的复杂度是 $O(n\log^2 n)$ 。
然而题目要求强制在线。
怎么办?
定期重构点分树?复杂度好像是 $O(n\sqrt n \log n)$ 。好像和暴力得分一样……
定期重构太naive了,我们给他升个级!
替罪羊树:当点分树的一个子树划分的过度不均匀的时候,重构子树。
恭喜你得到了一个 $O(n\log^3 n)$ 的算法。
接下来是写代码和调代码的欢♂乐时光。
可怕的是,这题还卡常数……
下面给出两份代码,一个是splay(68331ms的那个),一个是非旋Treap(107878ms)。
代码1 - splay
#pragma GCC optimize("Ofast","inline") #include <bits/stdc++.h> #define clr(x) memset(x,0,sizeof (x)) #define For(i,a,b) for (int i=a;i<=b;i++) #define Fod(i,b,a) for (int i=b;i>=a;i--) #define pb push_back #define mp make_pair #define fi first #define se second #define _SEED_ ('C'+'L'+'Y'+'A'+'K'+'I'+'O'+'I') #define outval(x) printf(#x" = %d\n",x) #define outvec(x) printf("vec "#x" = ");for (auto _v : x)printf("%d ",_v);puts("") #define outtag(x) puts("----------"#x"----------") using namespace std; typedef long long LL; LL read(){ LL x=0,f=0; char ch=getchar(); while (!isdigit(ch)) f|=ch=='-',ch=getchar(); while (isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48),ch=getchar(); return f?-x:x; } const int N=100005,INF=1.05e9,mod=1e9; const double checkval=0.80; namespace spl{ const int S=N*100; int son[S][2],fa[S],val[S],size[S]; int cnt=0; namespace cly{ int st[S],top=0; inline int new_node(){ return top?st[top--]:++cnt; } inline void Recover(int x){ st[++top]=x; son[x][0]=son[x][1]=fa[x]=val[x]=size[x]=0; } } using cly::new_node; using cly::Recover; #define ls son[x][0] #define rs son[x][1] int new_node(int v){ int x=new_node(); val[x]=v; return x; } inline void pushup(int x){ size[x]=size[ls]+size[rs]+1; } inline int wson(int x){ return son[fa[x]][1]==x; } void rotate(int x){ int y=fa[x],z=fa[y],L=son[y][1]==x,R=L^1; if (z) son[z][son[z][1]==y]=x; fa[x]=z,fa[y]=x,fa[son[x][R]]=y; son[y][L]=son[x][R],son[x][R]=y; pushup(y),pushup(x); } void splay(int x){ for (int y=fa[x];fa[x];rotate(x),y=fa[x]) if (fa[y]) rotate(wson(x)==wson(y)?y:x); } inline void Ins(int &a,int v){ register int x=a,c=0; int f=0; while (x){ c++; size[x]++; f=x; x=v<val[x]?ls:rs; } val[son[f][v>=val[f]]=x=new_node()]=v,fa[x]=f,size[x]=1; if (!a||c>30) splay(a=x); } int Query(int &rt,int v){ int ans=0,c=0; register int x=rt,p=0; while (x){ p=x,c++; if (val[x]<=v) ans+=size[ls]+1,x=rs; else x=ls; } if (p&&c>30) splay(rt=p); return ans; } void Remove(int x){ if (x) Remove(ls),Remove(rs),Recover(x); } int id[N]; void Build(int &x,int L,int R,int f){ if (L>R) return; int mid=(L+R)>>1; fa[x=id[mid]]=f; Build(ls,L,mid-1,x); Build(rs,mid+1,R,x); pushup(x); } void Build(int &x,vector <int> &v){ if (v.empty()) return; int n=0; sort(v.begin(),v.end()); for (auto i : v) id[++n]=new_node(i); Build(x,1,n,0); } #undef ls #undef rs } int Test,n; LL ans=0; vector <int> e[N]; int fa[N][20],depth[N],len[N]; int LCA(int x,int y){ if (depth[x]<depth[y]) swap(x,y); Fod(i,16,0) if (depth[x]-(1<<i)>=depth[y]) x=fa[x][i]; if (x==y) return x; Fod(i,16,0) if (fa[x][i]!=fa[y][i]) x=fa[x][i],y=fa[y][i]; return fa[x][0]; } int Dis(int x,int y){ return len[x]+len[y]-2*len[LCA(x,y)]; } int r[N]; namespace dt{ int fa[N],size[N],mxs[N],depth[N]; int rt[N],rtf[N]; int node_cnt=0; void Init(){ clr(fa),clr(size),clr(mxs),clr(depth),clr(rt),clr(rtf); depth[0]=-1,node_cnt++; size[1]=1,mxs[1]=depth[1]=rt[1]=0; spl::Ins(rt[1],0-r[1]); } int id[N],idc=0; void dfs(int x,int pre,int d){ id[++idc]=x; for (auto y : e[x]) if (y!=pre&&depth[y]>=d) dfs(y,x,d); } int sz[N],msz[N],RT,Size; void dfs2(int x,int pre){ sz[x]=1,msz[x]=0; for (auto y : e[x]) if (y!=pre&&!size[y]){ dfs2(y,x); sz[x]+=sz[y]; msz[x]=max(msz[x],sz[y]); } msz[x]=max(msz[x],Size-sz[x]); if (!RT||msz[x]<msz[RT]) RT=x; } vector <int> id1,id2; void dfs3(int x,int pre,int anc){ sz[x]=1; id1.pb(Dis(x,anc)-r[x]); if (fa[anc]) id2.pb(Dis(x,fa[anc])-r[x]); for (auto y : e[x]) if (y!=pre&&!size[y]) dfs3(y,x,anc),sz[x]+=sz[y]; } void build(int x,int f,int n){ RT=0,Size=n; dfs2(x,0); x=RT; fa[x]=f,depth[x]=depth[f]+1,size[x]=n,mxs[x]=msz[x]; id1.clear(),id2.clear(); dfs3(x,0,x); spl::Build(rt[x],id1); spl::Build(rtf[x],id2); for (auto y : e[x]) if (!size[y]) build(y,x,sz[y]); } void Rebuild(int x,int f){ idc=0; dfs(x,0,depth[x]); For(_t,1,idc){ int i=id[_t]; spl::Remove(rt[i]),spl::Remove(rtf[i]); depth[i]=size[i]=fa[i]=mxs[i]=rt[i]=rtf[i]=0; } build(x,f,idc); } void Ins(int x,int f){ static vector <int> v; fa[x]=f,depth[x]=depth[f]+1; rt[x]=rtf[x]=0; v.clear(); for (int i=x;i;i=fa[i]){ v.pb(i),size[i]++; mxs[fa[i]]=max(mxs[fa[i]],size[i]); spl::Ins(rt[i],Dis(i,x)-r[x]); if (fa[i]) spl::Ins(rtf[i],Dis(fa[i],x)-r[x]); } node_cnt++; reverse(v.begin(),v.end()); for (auto i : v) if (mxs[i]>checkval*size[i]){ Rebuild(i,fa[i]); break; } if (size[x]>1) ans+=spl::Query(rt[x],r[x])-1; for (int i=x,f,d;depth[i];i=f){ f=fa[i],d=Dis(f,x); ans+=spl::Query(rt[f],r[x]-d)-spl::Query(rtf[i],r[x]-d); } } } int main(){ Test=read(),n=read(); For(i,1,n){ int f=read()^(ans%mod),c=read(); r[i]=read(); if (!f){ dt::Init(); printf("%lld\n",ans); continue; } assert(1<=f&&f<i); e[i].pb(f),e[f].pb(i); fa[i][0]=f; For(j,1,16) fa[i][j]=fa[fa[i][j-1]][j-1]; depth[i]=depth[f]+1; len[i]=len[f]+c; dt::Ins(i,f); printf("%lld\n",ans); } return 0; }
代码2 - Treap(非旋)
#pragma GCC optimize("Ofast","inline") #include <bits/stdc++.h> #define clr(x) memset(x,0,sizeof (x)) #define For(i,a,b) for (int i=a;i<=b;i++) #define Fod(i,b,a) for (int i=b;i>=a;i--) #define pb push_back #define mp make_pair #define fi first #define se second #define _SEED_ ('C'+'L'+'Y'+'A'+'K'+'I'+'O'+'I') #define outval(x) printf(#x" = %d\n",x) #define outvec(x) printf("vec "#x" = ");for (auto _v : x)printf("%d ",_v);puts("") #define outtag(x) puts("----------"#x"----------") using namespace std; typedef long long LL; LL read(){ LL x=0,f=0; char ch=getchar(); while (!isdigit(ch)) f|=ch=='-',ch=getchar(); while (isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48),ch=getchar(); return f?-x:x; } const int N=100005,INF=1.05e9,mod=1e9; const double checkval=0.80; int randint(){ #ifdef windows return (rand()<<15)^rand(); #else return rand(); #endif } namespace Treap{ const int S=N*100; int son[S][2],val[S],ckv[S],size[S]; int cnt=0; namespace cly{ int st[S],top=0; inline int new_node(){ return top?st[top--]:++cnt; } inline void Recover(int x){ st[++top]=x,son[x][0]=son[x][1]=val[x]=size[x]=0; } } #define ls son[x][0] #define rs son[x][1] int new_node(int v){ int x=cly::new_node(); val[x]=v,ckv[x]=randint(),size[x]=1; return x; } void pushup(int x){ size[x]=size[ls]+size[rs]+1; } int Merge(int x,int y){ if (!x||!y) return x+y; if (ckv[x]<ckv[y]){ son[x][1]=Merge(son[x][1],y),pushup(x); return x; } else { son[y][0]=Merge(x,son[y][0]),pushup(y); return y; } } pair <int,int> Split(int x,int k){ if (!x) return mp(0,0); if (k<=size[ls]){ pair <int,int> p=Split(ls,k); ls=p.se,pushup(x); return mp(p.fi,x); } else { pair <int,int> p=Split(rs,k-size[ls]-1); rs=p.fi,pushup(x); return mp(x,p.se); } } int _Rank(int x,int v){ return x?(val[x]>v?_Rank(ls,v):size[ls]+1+_Rank(rs,v)):0; } int Rank(int x,int v){ return _Rank(x,v-1); } int Query(int x,int v){ return _Rank(x,v); } int id[N]; int tL[N],tR[N],lcnt,rcnt; void Build(int &x,int L,int R){ if (L>R) return; int Mi=L; For(i,L+1,R) if (ckv[id[i]]<ckv[id[Mi]]) Mi=i; swap(id[Mi],id[R]); x=id[R]; lcnt=rcnt=0; For(i,L,R-1) if (val[id[i]]<=val[x]) tL[++lcnt]=id[i]; else tR[++rcnt]=id[i]; int c=L-1; For(i,1,lcnt) id[++c]=tL[i]; int mid=c; For(i,1,rcnt) id[++c]=tR[i]; Build(ls,L,mid); Build(rs,mid+1,R-1); pushup(x); } void Build(int &x,vector <int> &v){ if (v.empty()) return; int n=0; for (auto i : v) id[++n]=new_node(i); Build(x,1,n); } void Ins(int &x,int v){ pair <int,int> p=Split(x,_Rank(x,v)); x=Merge(p.fi,Merge(new_node(v),p.se)); } void Remove(int x){ if (x) Remove(ls),Remove(rs),cly::Recover(x); } #undef ls #undef rs } int Test,n; LL ans=0; vector <int> e[N]; int fa[N][20],depth[N],len[N]; int LCA(int x,int y){ if (depth[x]<depth[y]) swap(x,y); Fod(i,16,0) if (depth[x]-(1<<i)>=depth[y]) x=fa[x][i]; if (x==y) return x; Fod(i,16,0) if (fa[x][i]!=fa[y][i]) x=fa[x][i],y=fa[y][i]; return fa[x][0]; } int Dis(int x,int y){ return len[x]+len[y]-2*len[LCA(x,y)]; } int r[N]; namespace dt{ int fa[N],size[N],mxs[N],depth[N]; int rt[N],rtf[N]; int node_cnt=0; void Init(){ clr(fa),clr(size),clr(mxs),clr(depth),clr(rt),clr(rtf); depth[0]=-1,node_cnt++; size[1]=1,mxs[1]=depth[1]=rt[1]=0; Treap::Ins(rt[1],0-r[1]); } int id[N],idc=0; void dfs(int x,int pre,int d){ id[++idc]=x; for (auto y : e[x]) if (y!=pre&&depth[y]>=d) dfs(y,x,d); } int sz[N],msz[N],RT,Size; void dfs2(int x,int pre){ sz[x]=1,msz[x]=0; for (auto y : e[x]) if (y!=pre&&!size[y]){ dfs2(y,x); sz[x]+=sz[y]; msz[x]=max(msz[x],sz[y]); } msz[x]=max(msz[x],Size-sz[x]); if (!RT||msz[x]<msz[RT]) RT=x; } vector <int> id1,id2; void dfs3(int x,int pre,int anc){ sz[x]=1; id1.pb(Dis(x,anc)-r[x]); if (fa[anc]) id2.pb(Dis(x,fa[anc])-r[x]); for (auto y : e[x]) if (y!=pre&&!size[y]) dfs3(y,x,anc),sz[x]+=sz[y]; } void build(int x,int f,int n){ RT=0,Size=n; dfs2(x,0); x=RT; fa[x]=f,depth[x]=depth[f]+1,size[x]=n,mxs[x]=msz[x]; id1.clear(),id2.clear(); dfs3(x,0,x); Treap::Build(rt[x],id1); Treap::Build(rtf[x],id2); for (auto y : e[x]) if (!size[y]) build(y,x,sz[y]); } void Rebuild(int x,int f){ idc=0; dfs(x,0,depth[x]); For(_t,1,idc){ int i=id[_t]; Treap::Remove(rt[i]),Treap::Remove(rtf[i]); depth[i]=size[i]=fa[i]=mxs[i]=rt[i]=rtf[i]=0; } build(x,f,idc); } void Ins(int x,int f){ static vector <int> v; fa[x]=f,depth[x]=depth[f]+1; rt[x]=rtf[x]=0; v.clear(); for (int i=x;i;i=fa[i]){ v.pb(i),size[i]++; mxs[fa[i]]=max(mxs[fa[i]],size[i]); Treap::Ins(rt[i],Dis(i,x)-r[x]); if (fa[i]) Treap::Ins(rtf[i],Dis(fa[i],x)-r[x]); } node_cnt++; reverse(v.begin(),v.end()); for (auto i : v) if (mxs[i]>checkval*size[i]){ Rebuild(i,fa[i]); break; } if (size[x]>1) ans+=Treap::Query(rt[x],r[x])-1; for (int i=x,f,d;depth[i];i=f){ f=fa[i],d=Dis(f,x); ans+=Treap::Query(rt[f],r[x]-d)-Treap::Query(rtf[i],r[x]-d); } } } int main(){ srand(_SEED_); Test=read(),n=read(); For(i,1,n){ int f=read()^(ans%mod),c=read(); r[i]=read(); if (!f){ dt::Init(); printf("%lld\n",ans); continue; } e[i].pb(f),e[f].pb(i); fa[i][0]=f; For(j,1,16) fa[i][j]=fa[fa[i][j-1]][j-1]; depth[i]=depth[f]+1; len[i]=len[f]+c; dt::Ins(i,f); printf("%lld\n",ans); } return 0; }
标签:rt,fa,55,void,紫荆花,depth,WC2014,int,size 来源: https://www.cnblogs.com/zhouzhendong/p/UOJ55.html