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] 来记录点。

#pragma comment(linker, "/STACK:10240000000000,10240000000000")
#include <cstdio>
#include <cstring>
#include <queue>
#include <cmath>
#include <map>
#include <algorithm>
using namespace std;
const int inf = 10000000;
typedef pair<int,int> pii;
typedef long long ll;
const int mod = 1000000+3;
int ni[mod];
void quick(int x){
	int ans = 1, tmp = x, y = mod-2;
	while(y){
		if(y&1)
			ans = (ll)ans * (ll)x % (ll)mod;
		x = (ll)x*(ll)x%(ll)mod;
		y>>=1;
	}
	ni[tmp] = ans;
}
template <class T>
inline bool rd(T &ret) {
	char c; int sgn;
	if(c=getchar(),c==EOF) return 0;
	while(c!='-'&&(c<'0'||c>'9')) c=getchar();
	sgn=(c=='-')?

-1:1;
	ret=(c=='-')?0:(c-'0');
	while(c=getchar(),c>='0'&&c<='9') ret=ret*10+(c-'0');
	ret*=sgn;
	return 1;
}
template <class T>
inline void pt(T x) {
	if (x <0) {
		putchar('-');
		x = -x;
	}
	if(x>9) pt(x/10);
	putchar(x%10+'0');
}
#define N 100005
pii ans;
void updata(int x, int y){
	if(x>y)swap(x,y);
	if(ans.first > x || ans.first==x && ans.second > y)
		ans = pii(x,y);
}
struct Edge{
	int to, nex;
}edge[N<<1];
int head[N], edgenum;
void init(){memset(head,-1,sizeof head); edgenum = 0;}
void add(int u, int v){
	Edge E = {v,head[u]};
	edge[edgenum] = E;
	head[u] = edgenum++;
}
int a[N], K, mul[N];
int n, siz[N];
int s[N], id[N], top;
int  has[mod], has_id[mod], tim;
bool vis[N];
void add_hash(int u, int multi_ans){
	if(has[multi_ans] == tim)
		has_id[multi_ans] = min(has_id[multi_ans], u);
	else {
		has[multi_ans] = tim;
		has_id[multi_ans] = u;
	}
}
int wval, wroot;
void getroot(int u, int fa){
	siz[u] = 1;
	int maxv = 0;
	for(int i = head[u]; ~i; i = edge[i].nex){
		int v = edge[i].to; if(v == fa || vis[v])continue;
		getroot(v, u);
		siz[u] += siz[v];
		maxv = max(maxv, siz[v]);
	}
	maxv = max(maxv, siz[0] - siz[u]);
	if(maxv < wval)wval = maxv, wroot = u;
}
int find_root(int u, int fa){ //找到子树的重心
	wval = 1000000;
	getroot(u, fa);
	return wroot;
}

void multi(int u, int fa){
	mul[u] = ((ll)a[u]*(ll)mul[fa])%(ll)mod;
	siz[u] = 1;
	s[top] = mul[u];	id[top++] = u;
	for(int i = head[u];~i;i=edge[i].nex){
		int v = edge[i].to; if(v == fa || vis[v])continue;
		multi(v, u);
		siz[u] += siz[v];
	}
}
void solve(int u){
	tim++;
	mul[u] = 1;
	vis[u] = 1;
	for(int i = head[u]; ~i; i = edge[i].nex){
		int v = edge[i].to; if(vis[v])continue;
		top = 0;
		multi(v, u);
		for(int i = 0; i < top; i++)
		{
			if(K == (ll)s[i]*(ll)a[u]%(ll)mod)
				updata(u, id[i]);
			int x = (ll)K * (ll)ni[ (ll)s[i] * (ll)a[u] % (ll)mod ] % (ll)mod;
			if(has[x] == tim)
				updata(id[i], has_id[x]);
		}
		for(int i = 0; i < top; i++)
		{
			add_hash(id[i], s[i]);
		}
	}
	for(int i = head[u];~i;i=edge[i].nex){
		int v = edge[i].to; if(vis[v])continue;
		siz[0] = siz[v];
		solve(find_root(v, u));
	}
}
void input(){
	init();
	for(int i = 1; i <= n; i++)rd(a[i]);
	for(int i = 1, u, v; i < n; i++)
	{
		rd(u); rd(v);
		add(u,v); add(v,u);
	}
}
int main() {
	tim = 0;
	memset(has, 0, sizeof has);
	for(int i = 0; i < mod; i++) quick(i);
	while(rd(n) && rd(K)) {
		input();
		ans.first = inf;
		memset(vis, 0, sizeof vis);
		siz[0] = n;
		solve(find_root(1,1));
		if(ans.first == inf)puts("No solution");
		else {
			pt(ans.first); putchar(' ');
			pt(ans.second); putchar('\n');
		}
	}
	return 0;
}

版权声明:本文博客原创文章。博客,未经同意,不得转载。

时间: 2024-07-28 18:55:31

HDU 4812 D Tree 树分区+逆+hash新位置的相关文章

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(树的点分治)

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 树分治+逆元处理

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 3333 Turing Tree 树状数组 离线查询

题意: 给你一个数列,然后有n个查询,问你给定区间中不同数字的和是多少. 思路还是比较难想的,起码对于蒟蒻我来说. 将区间按照先右端点,后左端点从小到大排序之后,对于每个查询,我只要维护每个数字出现的最后一次就可以了(这个结论稍微想一下就可以证明是正确的). 然后就是简单的点更新,区间求和问题了- #include <cstdio> #include <cstring> #include <iostream> #include <map> #include

hdu 3333 Turing Tree (树状数组+离线处理+离散化)

Turing Tree Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 3981    Accepted Submission(s): 1349 Problem Description After inventing Turing Tree, 3xian always felt boring when solving problems a

HDU 5379 Mahjong tree(树的遍历&amp;amp;组合数学)

本文纯属原创,转载请注明出处.谢谢. http://blog.csdn.net/zip_fan 题目传送门:http://acm.hdu.edu.cn/showproblem.php? pid=5379 Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Problem Description Little sun is an artist. Today he is playing

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 treat

HDU 3333 Turing Tree (树状数组)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3333 题意就是询问区间不同数字的和. 比较经典的树状数组应用. 1 //#pragma comment(linker, "/STACK:102400000, 102400000") 2 #include <algorithm> 3 #include <iostream> 4 #include <cstdlib> 5 #include <cstrin

hdu 3333 Turing Tree(树状数组离线操作)

Turing Tree Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 3904    Accepted Submission(s): 1325 Problem Description After inventing Turing Tree, 3xian always felt boring when solving problems