這應該暫時是個終結篇了...
最後在這裡討論lct的乙個常用操作:維護虛子樹資訊
這也是乙個常用操作
下面我們看一下如何來維護
以下內容**
對於乙個點x,如果我們對x進行access操作,那麼他的虛子樹內將包含且僅包含他原樹中子樹內除了他自己以外的所有點,這時如果我們維護了他的虛子樹資訊和,我們把這個資訊與他自己的資訊合併,我們就得到了他在原樹中的子樹資訊
在下面的討論中,我們發現我們可以同時維護乙個點的虛子樹資訊和lct子樹資訊來達到維護虛子樹資訊的目的
考慮乙個點的虛子樹資訊會在什麼情況下發生改變,乙個點的虛子樹資訊改變,當且僅當進行link或者access操作時。
在進行access操作時,我們會有更換乙個點的x右兒子的操作,這時我們要把x原來的右兒子的lct子樹資訊加入x的虛子樹資訊,把x的新的右兒子的lct子樹資訊從x的虛子樹資訊中減去
在進行link操作時,我們會先把點x換根,然後連一條x到y的虛邊,這時我們發現不僅y的虛子樹資訊需要加入x的lct子樹資訊,y的所有祖先的lct子樹資訊也需要更改,而這樣我們就沒法維護了,所以在進行link操作的時候我們需要把y也換根(其實access再splay就行了,不用換成根),這樣就只會對y的虛子樹資訊和lct子樹資訊產生影響
我們還需要維護乙個x的lct子樹的資訊和,x的lct子樹的資訊和就等於x的實兒子的lct子樹資訊和加上x的虛子樹的資訊和加上x自己,在splay的update函式中就可以直接維護
這樣我們就完成了對子樹資訊的維護
換根操作、cut操作和鏈修改操作並不影響我們上邊的討論,所以也是茲磁的
**結束
例:bzoj 4530大融合
#include #include #include #include #include #include #include #include using namespace std;
int c[100005][2];
int f[100005];
bool ttag[100005];
int si[100005];
int s[100005];
void update(int rt)
bool berot(int rt)
return 1;
}void reverse(int rt)
void pushdown(int rt)
if(c[rt][1])
ttag[rt]=0;
}} void repush(int rt)
pushdown(rt);
}void rotate(int rt)
if(!berot(fa))
else
}c[fa][ltyp]=c[rt][ltyp^1];
c[rt][ltyp^1]=fa;
f[c[fa][ltyp]]=fa;
f[fa]=rt;
f[rt]=ffa;
update(fa);
}void splay(int rt)
else
}rotate(rt);
}update(rt);
}void access(int rt)
}void makeroot(int rt)
void split(int st,int ed)
void link(int st,int ed)
inline int read()
while(ch>='0'&&ch<='9')
return x*f;
}int n,q;
char ss[5];
int main()
while(q--)
else
}return 0;
}
例:bzoj 3510首都
#include #include #include #include #include #include #include #include using namespace std;
int c[100005][2];
int f[100005];
int ff[100005];
int s[100005];
int si[100005];
bool ttag[100005];
int tot=0;
int findf(int x)
return ff[x]=findf(ff[x]);
}void update(int rt)
bool berot(int rt)
return 1;
}void reverse(int rt)
void pushdown(int rt)
}void repush(int rt)
pushdown(rt);
}void rotate(int rt)
if(!berot(fa))
else
}c[fa][ltyp]=c[rt][ltyp^1];
c[rt][ltyp^1]=fa;
f[c[fa][ltyp]]=fa;
f[fa]=rt;
f[rt]=ffa;
update(fa);
}void splay(int rt)
else
}rotate(rt);
}update(rt);
}void access(int rt)
}void makeroot(int rt)
void split(int st,int ed)
void link(int st,int ed)
int query(int rt)
else if(rt'9')
while(ch>='0'&&ch<='9')
return x*f;
}int n,m;
char ss[10];
int main()
while(m--)
else if(ss[0]=='q')
else
}return 0;
}
SPLAY,LCT學習筆記(五)
這一篇重點 lct的應用 例 bzoj 2631 tree2 國家集訓隊 lct模板操作之一,利用splay可以進行區間操作這一性質對維護懶惰標記,注意標記下傳順序和如何下傳 include include include include include include include includ...
SPLAY,LCT學習筆記(三)
前兩篇講述了splay模板操作,這一篇稍微介紹一下splay的實際應用 其實只有一道題,因為本蒟蒻就寫了這乙個 例 bzoj 1014火星人prefix 由於本蒟蒻不會字尾陣列,所以題目中給的提示完全沒看懂 不過並不影響我們做這道題,因為正解好像不用字尾陣列.首先,如果這題沒有插入和修改,那麼我們只...
SPLAY,LCT學習筆記(二)
接下來我們來填一下這個坑 回到我們的主題 noi 2005維修數列 我們剛剛討論了區間翻轉的操作方法,接下來我們來考慮區間插入和區間刪除的方法。所以當我們插入一段區間的時候,我們還是把這個區間的前驅和後繼轉上去,然後把這段區間插到左子樹就可以了 等等,怎麼插?乙個乙個往上扔?這顯然是不合理的。合理的...