Ideas ans Tricks

1.树上拓扑排序计数

结论$\dfrac{n!}{\prod\limits_{i=1}^n size_i}$

对于节点$i$,其子树随意排序的结果是$size[i]!$

但$i$需要排在第一位,只有$size[i]-1$个数可以任意排

乘上$\frac{1}{size[i]}$

2.DAG上的问题退化成有向树解决

如果转化为DAG问题的题目,如果边与边之间有传递关系

可以退化成树进行解决

在建树的时候需要关心的是某一个点的直接父亲是什么

如ATcoder的ABC158F

3.在基环树上DP

主要思想是将基环树上的环断开,然后做树形DP

最后处理这一条边对答案的影响

4.在数列上划分并要求划分区域递增的DP

基本的DP转移是

$dp[i][j]=max{dp[j][k]}+v(i)$

其中 $i$到$j$的区间和大于 $j$到$k$的区间和

朴素复杂度$O(n^3)$

可以使用单调队列优化到$O(n^2)$

利用固定j的取值

所以$i$增加的同时,$k$的范围也相应变大,利用单调队列和单指针维护

例如P3089

但如果$v(i)$有单调性,可优化到$O(n)$,如P5665

 5.求$depth[LCA(i,j)]$处理办法

将$i$到$root$的路径所有的点权值加一,然后询问$j$到$root$的路径的点权之和,就是$LCA$的深度

$LCA$可以看成两个点到根的两条链的第一个交点

6.LCT维护边权

将边看作一个点,将这个代表边的点的点权赋为这条边的边权,并将其他的点边权设为$0$或其他不影响答案的值

在连边或断边时,设这条边两端的端点为$u$,$v$,代表边的点编号为$id$

link(u,id),link(id,v);
cut(u,id),cut(id,v);

7.LCT维护子树信息

维护一个点由虚边连结的点的信息$si$,然后再维护所有的边(包括虚边和$Splay$上左右儿子)相连的儿子和自己的信息$s$

因为虚实边会随着LCT的操作不断变化

首先在$pushup$的时候,$s[x]=s[son[x][0]]+s[son[x][1]]+si[x]+val[x]$,保证$s$的值实时更新

$access$的时候因为去掉了$x$之前的实儿子(变为了虚儿子),增加了一个新的实儿子(由原来虚儿子变来),$si$一加一减,$s$不变化

for (int y=0;x;x=fa[x])
{
    splay(x);
    si[x]+=s[son[x][1]];
    son[x][1]=y;
    si[x]-=s[son[x][1]];
    pushup(x);
    y=x;
}//access

在$link$的时候增加了一条虚边,改变$y$的$si$,要注意要将$y$转到根上,以免改变其他节点的值

inline void link(int x,int y)
{
    makeroot(x);
    access(y);
    splay(y);
    fa[x]=y;
    si[y]+=s[x];
    pushup(y);
}

$cut$因为切掉的是实边,对$si$无影响,注意$pushup$即可

还有这里可以维护的信息是满足加减性的,如子树大小,子树权值和

但像子树权值最大值是不满足加减性的,不能维护(据说可以每个节点将$si$和$s$改成一棵平衡树)

在求出$x$子树的信息的时候,$access(x)$后取出$si[x]$即可

8.维护区间中位数

可以二分答案,将$>=x$的数标记为$1$,$=$当前二分的数,若某一个区间的和小于$0$,则这个区间的中位数$<=$当前二分的数

你可能感兴趣的:(Ideas ans Tricks)