洛谷P4219 - [BJOI2014]大融合
Description
初始有\(n(n\leq10^5)\)个孤立的点,进行\(Q(Q\leq10^5)\)次操作:
- 连接边\((u,v)\),保证\(u,v\)不连通。
- 询问有多少条简单路径经过边\((u,v)\)。
Solution
加边用lct,询问结果相当于\(p\)为根时的\((siz[p]-siz[q])\times siz[q]\)。
那么如何用lct维护子树大小呢?维护\(isiz[p]\)表示\(p\)在lct上的虚子树大小,\(siz[p]\)表示\(isiz[p]\)加上在辅助树上的实子树大小(子树大小也包括子树的虚子树和实子树)。当\(p=rt\)或\(p\)没有实子树时,\(siz[p]\)等于其原树上的子树大小。
如何维护\(isiz\)呢?只有当树的虚实划分变化时,\(isiz\)才会变化,也就是
access和
link。
access(p)中有一句
ch[p][1]=q,说明\(ch[p][1]\)变为虚子树,\(q\)变为实子树,则
isiz[p]+=siz[ch[p][1]]-siz[q]。
link(p,q)将\(p\)变为\(q\)的虚子树,因此\(q\)到\(q\)的根的\(isiz\)都要改变;因为不好实现所以
makeRt(q)之后再连接,并
isiz[q]+=siz[p]。
询问时,只要
makeRt(p),access(q),splay(q),此时\(q=rt\),\(p\)没有实子树,\(siz\)均正确。
时间复杂度\(O(Qlogn)\)。
Code
//[BJOI2014]大融合 #include <cstdio> #include <algorithm> using namespace std; int read() { int x=0; char ch=getchar(); while(ch<'0'||'9'<ch) ch=getchar(); while('0'<=ch&&ch<='9') x=x*10+ch-'0',ch=getchar(); return x; } int const N=1e5+10; int n,Q; int fa ,ch [2],siz ,isiz ; bool rev ; int wh(int p) {return p==ch[fa][1];} int notRt(int p) {return p==ch[fa[p]][wh(p)];} void rever(int p) {rev[p]^=1; swap(ch[p][0],ch[p][1]);} void update(int p) {siz[p]=siz[ch[p][0]]+siz[ch[p][1]]+isiz[p]+1;} void pushdw(int p) {if(rev[p]) rever(ch[p][0]),rever(ch[p][1]),rev[p]=false;} void rotate(int p) { int q=fa[p],r=fa[q],w=wh(p); fa[p]=r; if(notRt(q)) ch[r][wh(q)]=p; fa[ch[q][w]=ch[p][w^1]]=q; fa[ch[p][w^1]=q]=p; update(q),update(p); } void pushdwRt(int p) {if(notRt(p)) pushdwRt(fa[p]); pushdw(p);} void splay(int p) { pushdwRt(p); for(int q=fa[p];notRt(p);rotate(p),q=fa[p]) if(notRt(q)) rotate(wh(p)^wh(q)?p:q); } void access(int p) {for(int q=0;p;q=p,p=fa[p]) splay(p),isiz[p]+=siz[ch[p][1]]-siz[q],ch[p][1]=q,update(p);} void makeRt(int p) {access(p),splay(p),rever(p);} void link(int p,int q) {makeRt(p),makeRt(q); fa[p]=q,isiz[q]+=siz[p]; update(q);} long long query(int p,int q) {makeRt(p),access(q),splay(q); return (long long)siz[p]*(siz[q]-siz[p]);} int main() { n=read(),Q=read(); for(int i=1;i<=n;i++) siz[i]=1; for(int i=1;i<=Q;i++) { char opt[5]; scanf("%s",opt); int u=read(),v=read(); if(opt[0]=='A') link(u,v); else printf("%lld\n",query(u,v)); } return 0; }
P.S.
[p]比Icefox短了20行!- 洛谷P4219 [BJOI2014]大融合
- JZOJ 3766. 【BJOI2014】大融合
- 【BJOI 2014】大融合
- bzoj 4530: [Bjoi2014]大融合
- [BZOJ4530][Bjoi2014][LCT维护子树信息]大融合
- 4530: [Bjoi2014]大融合
- bzoj4530 [Bjoi2014]大融合(lct维护虚边信息)
- loj2230 「BJOI2014」大融合
- [Bjoi2014]大融合
- bzoj4530[Bjoi2014]大融合 线段树合并+dfs序+并查集
- [BZOJ4530][Bjoi2014]大融合(LCT)
- [BZOJ]4530 [BJOI2014] 大融合 LCT维护子树信息
- 【bzoj4530】[Bjoi2014]大融合 LCT维护子树信息
- bzoj4530 [Bjoi2014]大融合
- 【bzoj4530】【BJOI2014】【大融合】【dfs序+线段树合并+并查集】
- BZOJ.4530.[BJOI2014]大融合(LCT)
- 【BJOI2014】大融合 jzoj 3766 树链剖分+并查集
- 【bzoj4530】[Bjoi2014]大融合 并查集+线段树合并
- BZOJ 4530 [Bjoi2014]大融合 LCT维护子树信息
- BZOJ4530: [Bjoi2014]大融合