洛谷P4219 - [BJOI2014]大融合
阿新 • • 發佈:2018-03-14
連通 時間復雜度 += getchar can pro ret AC AD 沒有實子樹時,\(siz[p]\)等於其原樹上的子樹大小。
如何維護\(isiz\)呢?只有當樹的虛實劃分變化時,\(isiz\)才會變化,也就是
詢問時,只要 ,此時\(q=rt\),\(p\)沒有實子樹,\(siz\)均正確。
Portal
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\)
如何維護\(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)
時間復雜度\(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[N],ch[N][2],siz[N],isiz[N]; bool rev[N];
int wh(int p) {return p==ch[fa[p]][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.
比Icefox短了20行!
洛谷P4219 - [BJOI2014]大融合