HDU4916 Count on the path(树dp??)

这道题的题意其实有点略晦涩,定义f(a,b)为 minimum of vertices not on the path between vertices a and b. 其实它加一个minimum index of vertices应该会好理解一点吧。看了一下题解,还有程序,才理清思路。

首先比较直接的是如果两点的路径没有经过根节点1的话,那么答案就直接是1,否则的话就必然有从根节点出发的两条路径,题解里说的预处理出f[u]表示不在根节点到u的路径上的点的最小值,然后取f[u]和f[v]的最小值看了我半天。因为如果是这样的话,那么下面这个图不就可以轻易cha掉这种做法?

1->2  1->3  2->4  4->6  4->7  3->5  5->8  5->9

询问(6,8)的时候显然f(6)是3,f(8)是2,那么输出的答案就会是2,但实际上应该输出的是7。

后来仔细探究了才发现,f[u]存的只是  从不在根节点到u的路径的最小值(其中不包括根节点到别的子节点的路径),换言之上面的f[6]里只存了7,f[8]里只存了9,所以min(7,9)=7。

但是这个时候我们可能就会出错了,因为如果根节点如果连出去有第三条路径的话,那么这条路径的最小值我们是没有包含到的,所以对于根节点我们要存它最小值的子树,还有也要存对于每个节点它来自于哪个子树。

剩下的就是一个类似树dp的过程了。

然后题目还温馨提示了可能会超时,可能要写个输入挂什么的,所以写邻接表的可能都不能写vector的形式了吧。

#pragma warning(disable:4996)
#include <iostream>
#include <cstring>
#include <string>
#include <vector>
#include <cstdio>
#include <cmath>
#include <algorithm>
using namespace std;

#define maxn 1005000
#define inf 0x3f3f3f3f

int child[maxn][4];
int subtree[maxn];
int path[maxn];
int fa[maxn];
int bel[maxn];
int que[maxn];
int qh, qt;
int n, nQ;

int head[maxn];
int nxt[maxn<<1];
int vv[maxn<<1];
int tot;

void add_Edge(int u,int v)
{
	vv[tot] = v; nxt[tot] = head[u]; head[u] = tot++;
}

void bfs()
{
	qh = qt = 0;
	que[qt++] = 1; fa[1] = -1;
	while (qh < qt){
		int u = que[qh++];
		for (int i = head[u]; ~i; i=nxt[i]){
			int v = vv[i];
			if (v == fa[u]) continue;
			fa[v] = u;
			que[qt++] = v;
		}
	}
	for (int i = 0; i <= n; ++i){
		for (int j = 0; j < 4; ++j){
			child[i][j] = inf;
		}
	}
	for (int i = n - 1; i >= 0; --i){
		int u = que[i]; subtree[u] = u;
		for (int j = head[u]; ~j; j=nxt[j]){
			int v = vv[j];
			if (v == fa[u]) continue;
			child[u][3] = subtree[v];
			sort(child[u], child[u] + 4);
		}
		subtree[u] = min(subtree[u], child[u][0]);
	}

	qh = qt = 0;
	for (int i = head[1]; ~i; i=nxt[i]){
		int v = vv[i];
		que[qt++] = v;
		bel[v] = subtree[v];
		path[v] = inf;
	}
	while (qh < qt){
		int u = que[qh++];
		for (int i = head[u]; ~i; i=nxt[i]){
			int v = vv[i];
			if (v == fa[u]) continue;
			bel[v] = bel[u];
			if (subtree[v] == child[u][0]){
				path[v] = min(path[u], child[u][1]);
			}
			else{
				path[v] = min(path[u], child[u][0]);
			}
			que[qt++] = v;
		}
		path[u] = min(path[u], child[u][0]);
	}
}

int query(int qu, int qv){
	if (qu > qv) swap(qu, qv);
	if (qu != 1 && bel[qu] == bel[qv]) return 1;
	int i = 0;
	while (child[1][i] == bel[qu] || child[1][i] == bel[qv]){
		i++;
	}
	int ret = qu == 1 ? path[qv] : min(path[qu], path[qv]);
	ret = min(ret, child[1][i]);
	return ret;
}

inline void scan(int &n)
{
	char cc;
	for (; cc = getchar(), cc<‘0‘ || cc>‘9‘;);
	n = cc - ‘0‘;
	for (; cc = getchar(), cc >= ‘0‘&&cc <= ‘9‘;)
		n = n * 10 + cc - ‘0‘;
}

int main()
{
	while (cin >> n >> nQ){
		tot = 0; memset(head, -1, sizeof(head));
		int ui, vi;
		for (int i = 0; i < n - 1; ++i){
			//scan(ui); scan(vi);
			scanf("%d%d", &ui, &vi);
			add_Edge(ui, vi);
			add_Edge(vi, ui);
		}
		bfs();
		int last = 0;
		for (int i = 0; i < nQ; ++i){
			//scan(ui); scan(vi);
			scanf("%d%d", &ui, &vi);
			ui ^= last; vi ^= last;
			printf("%d\n", last=query(ui, vi));
		}
	}
	return 0;
}

HDU4916 Count on the path(树dp??)

时间: 2024-10-28 21:36:37

HDU4916 Count on the path(树dp??)的相关文章

hdu4916 Count on the path

调了好久.... •把树视为以1为根的有向树,然后将1删除 •原树变为一个森林,并且任一棵树的根节点均为原树中1的子节点 •只需要考虑最小编号前3小的三棵树 •记f[x][y]为去掉x和y两棵树后的最小值 •记dui[u]为u节点所在的树的根节点 •记dp[u]为在dui[u]这颗树中,不在路径<dui[u], u>上的节点编号最小值 •对于经过根节点的询问<u, v> •ans<u, v> = min(dp[u], dp[v], f[bel[u]][bel[v]])

HDU 4916 Count on the path

题意: 给定一棵树和m个询问  每个询问要求回答不在u和v两节点所形成的路径上的点的最小标号 思路: 一开始以为是LCA-  不过T了好几次-  后来发现不用LCA也可做 考虑每个询问u和v  如果他们的lca不是1  则1一定是答案  不过求lca会T  那么我们只需要在遍历树的时候给节点染色  染的颜色就是1的儿子的颜色  如果x这个点在y的子树中(y是1的儿子)那么他的颜色就是y 染完色后我们考虑答案是如何构成的 如图所示  答案即是  红色  蓝色  绿色的子树中节点的最小值  那么我们

【HDU 5647】DZY Loves Connecting(树DP)

pid=5647">[HDU 5647]DZY Loves Connecting(树DP) DZY Loves Connecting Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 262144/262144 K (Java/Others) Total Submission(s): 332    Accepted Submission(s): 112 Problem Description DZY has an unroote

Count on the path

Count on the path Time Limit: 5000/2500 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others) Problem Description bobo has a tree, whose vertices are conveniently labeled by 1,2,…,n. Let f(a,b) be the minimum of vertices not on the path bet

HDU6447 YJJ&#39;s Salesman 2018中国大学生程序设计竞赛 - 网络选拔赛1010 离散化+线段树+DP

YJJ's Salesman Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 253    Accepted Submission(s): 62 Problem Description YJJ is a salesman who has traveled through western country. YJJ is always on

2010辽宁省赛 NBUT 1222 English Game【字典树+DP】

[1222] English Game 时间限制: 1000 ms 内存限制: 131072 K 链接:Click Here! 问题描述 This English game is a simple English words connection game. The rules are as follows: there are N English words in a dictionary, and every word has its own weight v. There is a wei

uva 12452 Plants vs. Zombies HD SP (树DP)

Problem I: Plants vs. Zombies HD Super Pro Plants versus Zombies HD Super Pro is a game played not a grid, but on a connected graph G with no cycles (i.e., a tree). Zombies live on edges of the tree and chew through edges so that tree falls apart! Pl

POJ 2777 Count Color (线段树区间更新加查询)

Description Chosen Problem Solving and Program design as an optional course, you are required to solve all kinds of problems. Here, we get a new problem. There is a very long board with length L centimeter, L is a positive integer, so we can evenly d

hdu 3016 Man Down (线段树 + dp)

题目大意: 是男人就下一般层...没什么可以多说的吧. 注意只能垂直下落. 思路分析: 后面求最大值的过程很容易想到是一个dp的过程 . 因为每一个plane 都只能从左边 从右边下两种状态. 然后我们所需要处理的问题就是 ,你如何能快速知道往左边下到哪里,往右边下到哪里. 这就是线段树的预处理. 讲线段按照高度排序. 然后按照高度从小到大加入到树中. 然后去寻找左端点 和 右端点最近覆盖的线段的编号. #include <cstdio> #include <iostream> #