LCT

二次信任 提交于 2020-02-28 07:19:17

原理

懒得讲了

应用

维护链信息

luoguP1501

维护链懒标记的裸题

弹飞绵羊

每个点向右边弹到的点连边,超过\(n\)的所有点连向\(n+1\),最后形成一棵树,一个点\(splay\)到根后左儿子的数量(深度)就是最后答案

luoguP4332

记录一个节点的权值为\(0-3\)表示接受的\(1\)状态的数量

考虑每次更改一次节点状态,会自底部向上修改连续一段节点的状态

我们可以平衡树上二分找第一个权值为\(1/2\)的节点,也可以直接数组记录,然后把它换到根

注意修改完之后记录\(1/2\)的数组要交换,如果这个节点不存在就把整条链都修改

动态维护连通性

luoguP2147

裸题,\(link\)\(cut\)操作

luoguP2542

常见套路是删边变倒序加边

先将没有被删去的边连起来,我们把每条边中间加一个点,然后把新加的点且在原图中是割点的的点权都变成\(1\)

倒序操作序列,加边的时候如果两个点不连通就直接连边,让新加的点边权为\(1\)

否则把那个点到根的权值全部变为\(0\)

查询操作就是两点间的权值

bzoj2959

\(1\)操作:连接两个跑道,如果已经联通,那么就把路径上所有点用并查集合并,把所有点的权值给根节点

\(2\)操作:修改该节点根节点权值

3#操作:求链和

没写,口胡的(

动态维护生成树

水管局长

删边变逆序加边

\(link\)一条边时,如果两点已经联通,那么二分找到边权最大的边(边化点),然后替换掉

最小差值生成树

将边权从小到大排序插入\(LCT\),形成生成树之后每次把边权最小的边换掉,计算答案

[膜法森林](https://www.luogu.com.cn/problem/P2387

将边按一个关键字排序,维护另一个关键字的最小生成树

维护子树

大融合

求一条边两个端点虚子树点数之和

其实就两步,\(link\)的时候一个节点加上另一个节点总儿子数,\(access\)的时候加上原右子树减去新右子树

QTREE5

这是个神仙状态

\(dp1[x],dp2[x]\)分别表示在\(splay\)\(x\)子树里面深度最浅的点最近的白点的距离 和 深度最深的点最近的白点的距离

每个节点开个\(multiset\)维护下虚子树内白色点的最小距离

inline int fir(int x)
{
    return (!q[x].empty())?(*q[x].begin()):inf;
}
inline void pushup(int x)
{
    str[x]=str[son[x][0]]+str[son[x][1]]+1;
    dp1[x]=min(dp1[son[x][0]],str[son[x][0]]+min(val[x]?0:inf,min(fir(x),dp1[son[x][1]]+1)));
    dp2[x]=min(dp2[son[x][1]],str[son[x][1]]+min(val[x]?0:inf,min(fir(x),dp2[son[x][0]]+1)));
}

注意\(access\)的时候更新\(multiset\)

inline void access(int x)
{
    for(int y=0;x;x=f[y=x])
    {
        splay(x);
        q[x].insert(dp1[son[x][1]]+1);
        son[x][1]=y;
        it=q[x].lower_bound(dp1[son[x][1]]+1);
        if(it!=q[x].end()&&(*it)==dp1[son[x][1]]+1) q[x].erase(it);
        pushup(x);
    }
}

最后答案是将\(x\)旋转到根之后的\(dp2[x]\)

我们在这里选择不\(makeroot\),因为需要翻转子树很麻烦,修改时直接修改\(val[x]\)的状态然后\(pushup(x)\)

LOJ558

包括\(link\)\(cut\)操作的维护子树

注意点就是\(reverse\)的时候要把\(dp1\)\(dp2\)一起交换,同时\(cut\)的时候必须把连个点都喝边代表的虚点断开,否则边权会随机加到一棵\(splay\)

\(<=to\ be\ pigeon\)

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!