1. 程式人生 > >洛谷P4219 - [BJOI2014]大融合

洛谷P4219 - [BJOI2014]大融合

連通 時間復雜度 += getchar can pro ret AC AD

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\)

沒有實子樹時,\(siz[p]\)等於其原樹上的子樹大小。
如何維護\(isiz\)呢?只有當樹的虛實劃分變化時,\(isiz\)才會變化,也就是accesslinkaccess(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[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]大融合