HDU 4812 D Tree

Description

There is a skyscraping tree standing on the playground of Nanjing University of Science and Technology. On each branch of the tree is an integer (The tree can be treated as a connected graph with N vertices, while each branch can
be treated as a vertex). Today the students under the tree are considering a problem: Can we find such a chain on the tree so that the multiplication of all integers on the chain (mod 10 6 + 3) equals to K?

Can you help them in solving this problem?

Input

There are several test cases, please process till EOF.

Each test case starts with a line containing two integers N(1 <= N <= 10 5) and K(0 <=K < 10 6 + 3). The following line contains n numbers v i(1 <= v i < 10 6 + 3), where vi indicates the integer on vertex
i. Then follows N - 1 lines. Each line contains two integers x and y, representing an undirected edge between vertex x and vertex y.

Output

For each test case, print a single line containing two integers a and b (where a < b), representing the two endpoints of the chain. If multiply solutions exist, please print the lexicographically smallest one. In case no solution
exists, print “No solution”(without quotes) instead.

For more information, please refer to the Sample Output below.

Sample Input

5 60
2 5 2 3 3
1 2
1 3
2 4
2 5
5 2
2 5 2 3 3
1 2
1 3
2 4
2 5 

Sample Output

3 4
No solution 

Hint

 1. “please print the lexicographically smallest one.”是指: 先按照第一个数字的大小进行比较,若第一个数字大小相同,则按照第二个数字大小进行比较,依次类推。 2. 若出现栈溢出,推荐使用C++语言提交,并通过以下方式扩栈: #pragma comment(linker,"/STACK:102400000,102400000")
         

乘法逆元+树分治+hash,写完一A了,略开心。

#include<queue>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long LL;
const int INF = 0x7FFFFFFF;
const int mod = 1e6 + 3;
const int maxn = 2e5 + 10;
int n, K, x, y, inv[mod], h[mod], f[mod];

struct Tree
{
	int ft[maxn], nt[maxn], u[maxn], v[maxn], sz, n;
	int vis[maxn], cnt[maxn], mx[maxn], a, b, flag;
	void clear(int n)
	{
		this->n = n;	mx[0] = INF;
		a = b = sz = flag = 0;
		memset(h, 0, sizeof(h));
		for (int i = 1; i <= n; i++)
		{
			ft[i] = -1;
			vis[i] = 0;
			scanf("%d", &v[i]);
		}
	}
	void AddEdge(int x, int y)
	{
		u[sz] = y; nt[sz] = ft[x]; ft[x] = sz++;
	}
	int dfs(int x, int fa, int sum)
	{
		int ans = mx[x] = 0;
		cnt[x] = 1;
		for (int i = ft[x]; i != -1; i = nt[i])
		{
			if (vis[u[i]] || u[i] == fa) continue;
			int y = dfs(u[i], x, sum);
			if (mx[y]<mx[ans]) ans = y;
			cnt[x] += cnt[u[i]];
			mx[x] = max(mx[x], cnt[u[i]]);
		}
		mx[x] = max(mx[x], sum - cnt[x]);
		return mx[x] < mx[ans] ? x : ans;
	}
	void get(int x, int fa, int now, int kind)
	{
		if (!kind)
		{
			int y = (LL)K*inv[now] % mod;
			if (h[y] == flag)
			{
				if (a + b == 0) a = min(f[y], x), b = max(f[y], x);
				else
				{
					if (a > min(f[y], x)) a = min(f[y], x), b = max(f[y], x);
					else if (a == min(f[y], x) && b > max(f[y], x)) b = max(f[y], x);
				}
			}
		}
		else
		{
			if (h[now] != flag) h[now] = flag, f[now] = x;
			else f[now] = min(f[now], x);
		}
		for (int i = ft[x]; i != -1; i = nt[i])
		{
			if (vis[u[i]] || u[i] == fa) continue;
			get(u[i], x, (LL)now*v[u[i]] % mod, kind);
		}
	}
	void find(int x)
	{
		h[1] = ++flag;	f[1] = x;
		for (int i = ft[x]; i != -1; i = nt[i])
		{
			if (vis[u[i]]) continue;
			get(u[i], x, (LL)v[u[i]] * v[x] % mod, 0);
			get(u[i], x, v[u[i]], 1);
		}
	}
	void work(int x, int sum)
	{
		int y = dfs(x, -1, sum);
		vis[y] = 1;	 find(y);
		for (int i = ft[y]; i != -1; i = nt[i])
		{
			if (vis[u[i]]) continue;
			if (cnt[u[i]] > cnt[y]) cnt[u[i]] = sum - cnt[y];
			work(u[i], cnt[u[i]]);
		}
	}
}solve;

void read(int &x)
{
	char ch;
	while ((ch = getchar()) < '0' || ch > '9');
	x = ch - '0';
	while ((ch = getchar()) >= '0' && ch <= '9') x = x * 10 + ch - '0';
}

void init()
{
	inv[0] = 0;	inv[1] = 1;
	for (int i = 2; i < mod; i++) inv[i] = (LL)inv[mod%i] * (mod - mod / i) % mod;
}

int main()
{
	init();
	while (~scanf("%d%d", &n, &K))
	{
		solve.clear(n);
		for (int i = 1; i < n; i++)
		{
			scanf("%d%d", &x, &y);
			solve.AddEdge(x, y);
			solve.AddEdge(y, x);
		}
		solve.work(1, n);
		if (solve.a + solve.b) printf("%d %d\n", solve.a, solve.b);
		else printf("No solution\n");
	}
	return 0;
}
时间: 2024-08-28 23:08:56

HDU 4812 D Tree的相关文章

HDU 4812 D Tree 树分治+逆元处理

D Tree Problem Description There is a skyscraping tree standing on the playground of Nanjing University of Science and Technology. On each branch of the tree is an integer (The tree can be treated as a connected graph with N vertices, while each bran

hdu 4812 D Tree(树的点分治)

D Tree Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 102400/102400 K (Java/Others) Total Submission(s): 1687    Accepted Submission(s): 263 Problem Description There is a skyscraping tree standing on the playground of Nanjing University of

HDU 4812 D Tree 树分治+逆元+hash新姿势

题意: 给定n个点的树 K 下面n个数是点权 下面n-1行给出树边. 问: 是否存在一条路径使得路径上点权积 % mod  = K 若存在则输出路径的两端. 若存在多条路径则输出字典序最小的一条. 思路: 按树重心分治. 分成路径是否经过树重心. 然后用力码.. has[x] = u; 表示乘积为x 对应的点是u 但这样has就不能用计数器来优化清空. 所以用2个数组: has[x] = cnt; has_id[x] = u; 这样has里存的是乘积为x是否存在.has_id[x] 来记录点.

HDU 4812 D Tree 树分区+逆+hash新位置

意甲冠军: 特定n点树 K 以下n号码是正确的点 以下n-1行给出了树的侧. 问: 所以,如果有在正确的道路点图的路径 % mod  = K 如果输出路径的两端存在. 多条路径则输出字典序最小的一条. 思路: 按树重心分治. 分成路径是否经过树重心. 然后用力码. . has[x] = u; 表示乘积为x 相应的点是u 但这样has就不能用计数器来优化清空. 所以用2个数组: has[x] = cnt; has_id[x] = u; 这样has里存的是乘积为x是否存在.has_id[x] 来记录

hdu 4812 DTree (点分治)

D Tree Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 102400/102400 K (Java/Others)Total Submission(s): 3876    Accepted Submission(s): 743 Problem Description There is a skyscraping tree standing on the playground of Nanjing University of

hdu 5379 Mahjong tree(树形dp)

题目链接:hdu 5379 Mahjong tree 树形dp,每个节点最多有2个子节点为一棵节点数大于1的子树的根节点,而且要么后代的节点值都大于,要么都小于本身(所以tson不为0是,要乘2).对于K个单一节点的子节点,种类数即为全排K!.当一个节点没有兄弟节点时,以这个节点为根结点的子树,根可以选择最大或者最小. #pragma comment(linker, "/STACK:102400000,102400000") #include <cstdio> #inclu

HDU 4925 Apple Tree(推理)

HDU 4925 Apple Tree 题目链接 题意:给一个m*n矩阵种树,每个位置可以选择种树或者施肥,如果种上去的位置就不能施肥,如果施肥则能让周围果树产量乘2,问最大收益 思路:推理得到肯定是果树和肥料交叉种好,类似国际象棋棋盘,黑的种,白的施肥,由于格子数不多,直接去枚举每个位置即可.如果题目格子数多的话,其实也可以推出公式一步得到答案 代码: #include <cstdio> #include <cstring> const int d[4][2] = {{0, 1}

HDU 4925 Apple Tree (瞎搞)

找到规律,各一个种一棵树,或者施肥.先施肥,先种树一样. Apple Tree Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 262144/262144 K (Java/Others) Total Submission(s): 197    Accepted Submission(s): 135 Problem Description I've bought an orchard and decide to plant some

hdu 4925 Apple Tree

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4925 思路:直接计算坐标和,如果为奇数就种树,但要注意行或列为1的情况. 写啦两种代码:一种直接判断计算的,另一种优化计算的 code1: #include<cstdio> #include<iostream> #include<algorithm> #include<cmath> using namespace std; int main() { int T;