• 【YBTOJ】【Luogu P2634】[国家集训队]聪聪可可


    链接:

    洛谷

    题目大意:

    在一棵 (n) 个节点的树上随机选两个点(可以选同一个),求两点路径长度和是 (3) 的倍数的期望个数。

    正文:

    点分治经典题。在板子的基础上,求两点之间路径长度时可以不断模三,那么对答案的统计时,(ans=2t_1cdot t_2+{t_0}^2),其中 (t_i) 表示路径长度和模三为 (i) 的点对数量。

    代码:

    const int N = 100010;
    
    int n;
    
    struct edge
    {
    	int to, nxt, val;
    }e[N << 1];
    int head[N], tot;
    
    void add(int u, int v, int w)
    {
    	e[++tot] = (edge) {v, head[u], w}, head[u] = tot;
    }
    
    bool vis[N];
    int rt, sum, ans;
    int sz[N], son[N];
    
    void getRoot (int u, int fa)
    {
    	sz[u] = 1; son[u] = 0;
    	for (int i = head[u]; i; i = e[i].nxt)
    	{
    		int v = e[i].to;
    		if (vis[v] || v == fa) continue;
    		getRoot(v, u);
    		sz[u] += sz[v];
    		son[u] = max(son[u], sz[v]);
    	}
    	son[u] = max(son[u], sum - sz[u]);
    	if (son[u] < son[rt]) rt = u;
    }
    
    int dis[N], dissort[4];
    
    void getDis (int u, int fa)
    {
    	dissort[dis[u]] ++;
    	for (int i = head[u]; i; i = e[i].nxt)
    	{
    		int v = e[i].to;
    		if (vis[v] || v == fa) continue;
    		dis[v] = (dis[u] + e[i].val) % 3;
    		getDis(v, u);
    	}
    }
    
    int calc (int u, int val)
    {
    	dis[u] = val;
    	dissort[0] = dissort[1] = dissort[2] = 0;
    	getDis(u, 0);
    	return dissort[0] * dissort[0] + 2 * dissort[1] * dissort[2];
    }
    
    void solve (int u)
    {
    	ans += calc(u, 0);
    	vis[u] = 1;
    	for (int i = head[u]; i; i = e[i].nxt)
    	{
    		int v = e[i].to;
    		if (vis[v]) continue;
    		ans -= calc (v, e[i].val);
    		
    		// Figure 1:
    		sum = sz[v], son[0] = n, rt = 0;
    		getRoot (v, u), solve(rt);
    	}
    }
    
    int gcd(int a, int b)
    {
    	return b? gcd(b, a % b): a;
    }
    
    int main()
    {
    	scanf ("%d", &n);
    	for (int i = 1; i < n; i++)
    	{
    		int u, v, w;
    		scanf ("%d%d%d", &u, &v, &w); w %= 3;
    		add(u, v, w), add(v, u, w);
    	}
    	son[0] = sum = n, getRoot(1, 0), solve(rt);
    	int g = gcd(ans, n * n);
    	printf ("%d/%d
    ", ans / g, n * n / g);
    	return 0;
    }
    
  • 相关阅读:
    elasticsearch数据迁移
    Leetcode <剑指 Offer 64. 求1+2+…+n>
    Leetcode <27.移除元素>
    Leetcode <7.整数反转>
    Leetcode <1. 两数之和>
    python实现对于告警规则的判断思路
    Python实现密码生成器
    Autojs 打包APP+签名
    Docker 文档整理
    Pycharm 连接Linux远程开发
  • 原文地址:https://www.cnblogs.com/GJY-JURUO/p/14520529.html
Copyright © 2020-2023  润新知