1. 程式人生 > >洛谷 P4219 [BJOI2014]大融合 解題報告

洛谷 P4219 [BJOI2014]大融合 解題報告

P4219 [BJOI2014]大融合

題目描述

小強要在\(N\)個孤立的星球上建立起一套通訊系統。這套通訊系統就是連線\(N\)個點的一個樹。 這個樹的邊是一條一條新增上去的。在某個時刻,一條邊的負載就是它所在的當前能夠 聯通的樹上路過它的簡單路徑的數量。

現在,你的任務就是隨著邊的新增,動態的回答小強對於某些邊的負載的 詢問。

輸入輸出格式

輸入格式:

第一行包含兩個整數 \(N, Q\),表示星球的數量和操作的數量。星球從 \(1\) 開始編號。

接下來的 \(Q\) 行,每行是如下兩種格式之一:

  • A x y 表示在 \(x\)\(y\) 之間連一條邊。保證之前 \(x\)
    \(y\) 是不聯通的。
  • Q x y表示詢問 \((x,y)\) 這條邊上的負載。保證 \(x\)\(y\) 之間有一條邊。

輸出格式:

對每個查詢操作,輸出被查詢的邊的負載。

說明

對於所有資料,\(1≤N,Q≤10^5\)


LCT維護子樹資訊,漲見識了。

\(sizx_i\)代表虛邊連的兒子的大小。

然後\(updata\)這樣寫

void updata(int now){siz[now]=siz[ls]+siz[rs]+sizx[now]+1;}

然後是在\(access\)的時候修改一下虛邊兒子大小,在\(link\)的時候要把兩個樹都選上去保證沒得父親,因為我們不想把被連的那個點的資訊再向上更新。

維護最值可以在每個點開個平衡樹


Code:

#include <cstdio>
#define ll long long
#define ls ch[now][0]
#define rs ch[now][1]
#define fa par[now]
const int N=1e5+10;
int ch[N][2],par[N],siz[N],sizx[N],tag[N],s[N],tot,tmp;
bool isroot(int now){return ch[fa][0]==now||ch[fa][1]==now;}
int identity(int now){return ch[fa][1]==now;}
void updata(int now){siz[now]=siz[ls]+siz[rs]+sizx[now]+1;}
void Reverse(int now){tag[now]^=1,tmp=ls,ls=rs,rs=tmp;}
void connect(int f,int now,int typ){ch[fa=f][typ]=now;}
void pushdown(int now)
{
    if(tag[now])
    {
        if(ls) Reverse(ls);
        if(rs) Reverse(rs);
        tag[now]^=1;
    }
}
void Rotate(int now)
{
    int p=fa,typ=identity(now);
    connect(p,ch[now][typ^1],typ);
    if(isroot(p)) connect(par[p],now,identity(p));
    else fa=par[p];
    connect(now,p,typ^1);
    updata(p),updata(now);
}
void splay(int now)
{
    while(isroot(now)) s[++tot]=now,now=fa;
    s[++tot]=now;
    while(tot) pushdown(s[tot--]);
    now=s[1];
    for(;isroot(now);Rotate(now))
        if(isroot(fa))
            Rotate(identity(now)^identity(fa)?now:fa);
}
void access(int now)
{
    for(int las=0;now;las=now,now=fa)
        splay(now),sizx[now]+=siz[rs]-siz[las],rs=las;
}
void evert(int now){access(now),splay(now),Reverse(now);}
void link(int u,int v){evert(u),access(v),splay(v),par[u]=v,sizx[v]+=siz[u],updata(v);}
void cat(int u,int v){evert(u),access(v),splay(v),ch[v][0]=par[u]=0,updata(v);}
int query(int now){access(now),splay(now);return siz[now];}
int n,q;
int main()
{
    scanf("%d%d",&n,&q);
    for(int i=1;i<=n;i++) siz[i]=1;
    char op[3];
    for(int u,v,i=1;i<=q;i++)
    {
        scanf("%s%d%d",op,&u,&v);
        if(op[0]=='Q') cat(u,v),printf("%lld\n",1ll*query(u)*query(v)),link(u,v);
        else link(u,v);
    }
    return 0;
}

2018.12.7