虚树+树形dp
虚树一类问题是指多次询问,每次询问的点数较少,如果我们每次都对整棵树进行遍历,那么自然是不行的,这时我们就构造出一棵虚树来降低复杂度
具体构建就是把一些无用的点缩起来。我们考虑对于一个点包括自己和这个点的子树,我们怎么构建虚树。
我们把所有点按dfs序排序,也就是模拟出dfs的过程,然后用一个栈维护。
每次加入新点x,我们求出和栈顶y的lca,t,如果dfn[t]>=dfn[y],那么说明x在y的下面,那么直接入栈就行了,否则就不在同一条子树的链中,这时我们就要像dfs一样退栈,这时要注意
黑点是需要构建的点,当我们加入4号点时,栈里有1,3,4,加入5的时候,我们发现需要退栈,我们先弹掉4,把3->4连边,然后就需要注意,我们不能把1->3,而需要把2->3,于是我们判断dfn[lca]和dfn[st[top-1]]的大小关系来决定如何连边,再把3弹掉,然后如果栈顶不是lca,那么就把lca=2加入栈里,继续进行这个过程
最后就是树形dp了
其实虚树的构建很像dfs的过程
#include<cstdio> #include<cstring> #include<algorithm> #include<vector> #include<iostream> using namespace std; const int N = 250010; struct edge { int nxt, to; long long w; } e[N << 1]; int n, m, cnt = 1, tot, top; int head[N], dfn[N], dep[N], fa[N], Top[N], size[N], a[N], st[N], mark[N], son[N]; long long val[N]; vector<int> G[N]; namespace IO { const int Maxlen = N * 50; char buf[Maxlen], *C = buf; int Len; inline void read_in() { Len = fread(C, 1, Maxlen, stdin); buf[Len] = '