HNOI2014 世界树 基于虚树的树形动态规划
来源:互联网 发布:便携式安全座椅 知乎 编辑:程序博客网 时间:2024/06/04 18:33
题目大意
给你一个
解体思路
一看到题目,
为了减少树中节点的个数,虚树就是个能满足这个要求的数据结构,对于这题,我们需要考虑的就只有那
那么我们把虚树中的关键点成为黑点,其它称为白点。对于每个白点,我们需要先找出一个离它最近的黑点,作为控制它的点,这个可以用树形dp上下各扫一遍线性的完成。那我们考虑一下虚树上的每条边:
连接两个黑点:直接找分界点即可。
连接一个黑点,一个白点:如果控制这个白点的就是这个黑点,显然这条边上的所有点都属与这个黑点。如果不是那我们就求控制这个白点的黑点和这个黑点之间路径的分界点,显然这个分界点肯定在这条边上,那找到分界点后直接分配边上的点就可以了。
连接两个白点:找到控制这两个白点的黑点,那么就跟第二种情况一样了。
至此我们就有了线性求出每个关键点包含的点了,并且是与
程序
//YxuanwKeith#include <cstring>#include <cstdio>#include <algorithm>using namespace std;const int MAXN = 3e5 + 5;int tot, Last[MAXN], Next[MAXN * 2], Go[MAXN * 2];int N, Q, Time, L[MAXN], R[MAXN], Close[MAXN], tag[MAXN], Flag[MAXN], Num[MAXN], Clear[MAXN];int Fa[MAXN][21], Deep[MAXN], Size[MAXN], Dist[MAXN], D[MAXN], P[MAXN], Pre[MAXN], Ans[MAXN];bool Cmp(int A, int B) { return L[A] < L[B];}void Link(int u, int v) { Next[++ tot] = Last[u], Last[u] = tot, Go[tot] = v;}void Init() { scanf("%d", &N); for (int i = 1; i < N; i ++) { int u, v; scanf("%d%d", &u, &v); Link(u, v), Link(v, u); }}void Dfs(int Now, int Pre) { L[Now] = ++ Time, Fa[Now][0] = Pre; Size[Now] = 1, Deep[Now] = Deep[Pre] + 1; for (int p = Last[Now]; p; p = Next[p]) { int v = Go[p]; if (v == Pre) continue; Dfs(v, Now); Size[Now] += Size[v]; } R[Now] = Time;}void PreFa() { for (int j = 1; j <= 20; j ++) for (int i = 1; i <= N; i ++) Fa[i][j] = Fa[Fa[i][j - 1]][j - 1];}int GetPre(int Now, int Goal) { for (int i = 20; i + 1; i --) if (Deep[Fa[Now][i]] >= Goal) Now = Fa[Now][i]; return Now;}int Lca(int u, int v) { if (Deep[u] < Deep[v]) swap(u, v); for (int i = 20; i + 1; i --) if (Deep[Fa[u][i]] >= Deep[v]) u = Fa[u][i]; if (u == v) return u; for (int i = 20; i + 1; i --) if (Fa[u][i] != Fa[v][i]) u = Fa[u][i], v = Fa[v][i]; return Fa[u][0];}int Dis(int A, int B) { return Deep[A] + Deep[B] - Deep[Lca(A, B)] * 2;}void Update(int Now, int From, int Ask) { From = Close[From]; int dis = Dis(Now, From); if (tag[Now] != Ask || Dist[Now] > dis || Dist[Now] == dis && Close[Now] > From) { tag[Now] = Ask; Close[Now] = From; Dist[Now] = Dis(Now, From); }}void PreDown(int Ask, int New) { for (int i = 2; i <= New; i ++) Update(P[i], Pre[P[i]], Ask);}void PreUp(int Ask, int New) { for (int i = New; i; i --) { int Now = P[i]; for (int p = Last[Now]; p; p = Next[p]) Update(Now, Go[p], Ask); }}void Solve(int Id1, int Id2, int Side1, int Side2, int Below) { Num[Id2] += 1; if (Fa[Side2][0] == Side1) return; int Len = Dis(Id1, Id2) - 1; int Mid = GetPre(Side2, Deep[Id2] - (Len + 1) / 2); if (Len & 1 && Id2 > Id1) Mid = GetPre(Side2, Deep[Mid] + 1); Num[Id1] += Size[Below] - Size[Mid]; Num[Id2] += Size[Mid] - Size[Side2];}void GetAns(int Now, int Ask) { int Son = 0; for (int p = Last[Now]; p; p = Next[p]) { int v = Go[p]; if (Clear[Close[v]] != Ask) Num[Close[v]] = 0, Clear[Close[v]] = Ask; int Below = GetPre(v, Deep[Now] + 1); Son += Size[Below]; if (Close[Now] == Close[v]) { Num[Close[Now]] += Size[Below] - Size[v] + 1; } else Solve(Close[Now], Close[v], Now, v, Below); GetAns(Go[p], Ask); } Num[Close[Now]] += (Size[Now] - Son - 1);}void Solve() { Dfs(1, 0); PreFa(); scanf("%d", &Q); for (int Ask = 1; Ask <= Q; Ask ++) { int M; memset(Last, 0, sizeof Last); tot = 0; scanf("%d", &M); for (int i = 1; i <= M; i ++) { scanf("%d", &P[i]); Ans[i] = P[i]; Flag[P[i]] = Ask; Close[P[i]] = P[i], tag[P[i]] = Ask, Dist[P[i]] = 0; } sort(P + 1, P + 1 + M, Cmp); int All = M, New = 0; for (int i = 1; i <= M - 1; i ++) P[++ All] = Lca(P[i], P[i + 1]); sort(P + 1, P + All + 1, Cmp); for (int i = 1; i <= All; i ++) if (P[i] != P[i - 1]) P[++ New] = P[i]; D[0] = 0; for (int i = 1; i <= New; i ++) { int Now = P[i]; Last[Now] = 0; while (D[0] && (R[Now] < L[D[D[0]]] || L[Now] > R[D[D[0]]])) -- D[0]; if (D[0] > 0) Link(D[D[0]], Now), Pre[Now] = D[D[0]]; D[++ D[0]] = Now; } PreUp(Ask, New); PreDown(Ask, New); Num[Close[P[1]]] = Size[1] - Size[P[1]] + 1, Clear[Close[P[1]]] = Ask; GetAns(P[1], Ask); for (int i = 1; i <= M; i ++) printf("%d ", Num[Ans[i]]); printf("\n"); }}int main() { freopen("worldtree.in", "r", stdin), freopen("worldtree.out", "w", stdout); Init(); Solve();}
1 0
- HNOI2014 世界树 基于虚树的树形动态规划
- [ BZOJ3572 ] [ Hnoi2014 ] [ 虚树 ] [ 树形DP ] 世界树
- [BZOJ3572][HNOI2014]世界树-虚树+树形DP
- bzoj 3572: [Hnoi2014]世界树 (虚树+树形DP+LCA)
- [BZOJ3572][Hnoi2014]世界树(虚树+树形dp+二分+lca)
- bzoj3572: [Hnoi2014]世界树
- bzoj3572: [Hnoi2014]世界树
- bzoj3572: [Hnoi2014]世界树
- [BZOJ3572][HNOI2014]世界树
- [BZOJ3572] [Hnoi2014]世界树
- bzoj3572: [Hnoi2014]世界树
- [bzoj3572][HNOI2014]世界树
- 【HNOI2014】世界树
- 3572: [Hnoi2014]世界树
- 【HNOI2014】bzoj3572 世界树
- 【BZOJ3572】【Hnoi2014】世界树 虚树
- bzoj 3572[HNOI2014]世界树
- BZOJ 3572: [Hnoi2014]世界树
- Android DrawerLayout简单实现侧滑菜单
- Servlet 生命周期、工作原理
- struts2 fileUpload glassfish 上载文件限制修
- hibernate框架知识
- Android的线程和线程池
- HNOI2014 世界树 基于虚树的树形动态规划
- 安装MySQL5.5的错误Error Nr.1045解决方案
- Dom4j解析xml总结
- 85. Maximal Rectangle
- 时钟类的构造函数
- Python中可变函数的说明
- 55. Jump Game
- c读取文件的运用(转)
- CFUUIDRef theUUID = CFUUIDCreate(NULL); CFStringRef guid = CFUUIDCreateString(NULL, theUUID);