CF715C Digit Tree

题面

题解

树上求点对数目的题大多都是点分治解决

路径统计中有一个问题,如果现在求出从上到下的链长$a$,从下到上的链长$b$和深度$c$,

则:

$ a \times10^c + b\equiv0(mod\;m) $

两边同除以$c$,得

$ a + b\times10^{-c}\equiv0(mod\;m)\;\;(\because gcd(10,\;m) = 1) $

于是可以很好维护了。

代码

#include<cstdio>
#include<cstring>
#include<cctype>
#include<algorithm>
#include<map>
#define RG register
#define file(x) freopen(#x".in", "r", stdin);freopen(#x".out", "w", stdout);
#define clear(x, y) memset(x, y, sizeof(x))

inline int read()
{
	int data = 0, w = 1; char ch = getchar();
	while(ch != '-' && (!isdigit(ch))) ch = getchar();
	if(ch == '-') w = -1, ch = getchar();
	while(isdigit(ch)) data = data * 10 + (ch ^ 48), ch = getchar();
	return data * w;
}

const int maxn(1e5 + 10);
struct edge { int next, to, dis; } e[maxn << 1];
int head[maxn], e_num, n, m, size[maxn], root;
int Size, min, vis[maxn], Pow[maxn], cnt;

inline void Init()
{
	clear(head, 0); e_num = 0, Pow[0] = 1;
	for(RG int i = 1; i <= n; i++) Pow[i] = 10ll * Pow[i - 1] % m;
}

#undef clear

inline void add_edge(int from, int to, int dis)
{
	e[++e_num] = (edge) {head[from], to, dis};
	head[from] = e_num;
}

std::pair<int, int> digit[maxn << 1];
std::map<int, long long> tong;
void getRoot(int x, int fa)
{
	size[x] = 1;
	int tot = 0;
	for(RG int i = head[x]; i; i = e[i].next)
	{
		int to = e[i].to;
		if(to == fa || vis[to]) continue;
		getRoot(to, x); tot = std::max(tot, size[to]);
		size[x] += size[to];
	}
	tot = std::max(tot, Size - size[x]);
	if(tot < min) min = tot, root = x;
}

void getDep(int x, int fa, long long d1, long long d2, int dep)
{
	if(dep >= 0) ++tong[d1], digit[++cnt] = std::make_pair(d2, dep);
	for(RG int i = head[x]; i; i = e[i].next)
	{
		int to = e[i].to, dis = e[i].dis; if(to == fa || vis[to]) continue;
		getDep(to, x, (d1 + 1ll * Pow[dep + 1] * dis) % m,
				(d2 * 10 + dis) % m, dep + 1);
	}
}

void exgcd(long long a, long long b, long long &gcd, long long &x, long long &y)
{
	!b ? gcd = a, x = 1, y = 0 : (exgcd(b, a % b, gcd, y, x), y -= x * (a / b));
}

inline long long Inv(int a, int Mod)
{
	long long d, x, y; exgcd(a, Mod, d, x, y);
	return d == 1 ? (x % Mod + Mod) % Mod : -1;
}

long long calc(int x, int d)
{
	long long ans = 0; tong.clear(), cnt = 0;
	if(d) getDep(x, 0, d % m, d % m, 0);
	else getDep(x, 0, 0, 0, -1);
	for(RG int i = 1; i <= cnt; i++)
	{
		long long tmp = (-digit[i].first * 1ll *
		Inv(Pow[digit[i].second + 1], m) % m + m) % m;
		if(tong.find(tmp) != tong.end()) ans += tong[tmp];
		if(!d) ans += (digit[i].first == 0);
	}
	if(d == 0) ans += tong[0];
	return ans;
}

long long ans;
void dfs(int x)
{
	ans += calc(x, 0);
	vis[x] = true;
	for(RG int i = head[x]; i; i = e[i].next)
	{
		int to = e[i].to;
		if(vis[to]) continue;
		ans -= calc(to, e[i].dis);
		min = n, Size = size[to];
		getRoot(to, x); dfs(root);
	}
}

int main()
{
	while(~scanf("%d%d", &n, &m))
	{
		Init(); Size = min = n;
		for(RG int i = 1, a, b, c; i < n; i++)
			a = read() + 1, b = read() + 1, c = read(),
			  add_edge(a, b, c), add_edge(b, a, c);
		ans = 0; memset(vis, 0, sizeof(vis));
		getRoot(1, 0); dfs(root);
		printf("%I64d\n", ans);
	}
	return 0;
}

转载于:https://www.cnblogs.com/cj-xxz/p/10161333.html

nvm是一个用来管理nodejs版本的工具,可以通过nvm来安装和切换不同版本的nodejs。首先,你需要卸载你原有的node版本,然后删除相关的文件和环境变量。接下来,你可以从nvm的官方网站下载nvm安装程序,并按照指示进行安装。安装完成后,你可以使用nvm命令来安装指定版本的nodejs,例如使用"nvm install \[node的版本号\]"来安装14.17.2版本的nodejs。安装完成后,你可以使用"nvm use \[node的版本号\]"来切换到指定版本的nodejs。最后,你可以使用"node -v"命令来验证nodejs是否安装成功。希望这些步骤对你有帮助。 #### 引用[.reference_title] - *1* [nvm下载安装+使用教程(管理nodejs版本,实现按需加载版本)](https://blog.csdn.net/m0_54355172/article/details/126793854)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [使用NVM安装NodeJS并解决npm下载依赖失效问题(最全流程)](https://blog.csdn.net/qq_45225759/article/details/124481233)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control,239^v3^insert_chatgpt"}} ] [.reference_item] - *3* [利用nvm下载nodejs](https://blog.csdn.net/weixin_45113182/article/details/127875685)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值