• 【JZOJ 5814】【NOIP提高A组模拟2018.8.14】 树


    题目大意:

    给定 (Q) 个询问,每个询问给出 (u,v),求从 (u) 走到 (v) 的期望步数。

    正文:

    (f_i) 表示第 (i) 个点到其父节点的期望步数,(g_i) 表示其父节点到第 (i) 个点的期望步数。则有:

    [f_x=frac{1}{deg_x}+sum_{yin son(x)}frac{1+f_x+f_y}{deg_x} \ g_x=frac{1}{deg_{fa(x)}}+frac{1+g_x+g_{fa(x)}}{deg_{fa(x)}}+sum_{yin son(fa(x))|y e x}frac{g_x+1+f_y}{deg_{fa(x)}} ]

    (deg_x) 表示节点 (x) 的度)

    化简这两个式子:

    [egin{aligned}f_xcdot deg_x &=1+sum_{yin son(x)}f_x+1+f_y\f_xcdot deg_x&=dge_x+(deg_x-1)f_x+sum_{yin son(x)}f_y\ f_x&=deg_x+sum_{yin son(x)}f_yend{aligned} ]

    [egin{aligned}g_xcdot deg_{fa(x)}&=2+g_x+g_{fa(x)}+sum_{yin son(fa(x))|y e x}f_y\ g_xcdot deg_{fa(x)}&=deg_{fa(x}+(deg_{fa(x)}-1)g_x+g_{fa(x})+sum_{yin son(fa(x))|y e x}f_y\g_x&=deg_{fa(x)}+g_{fa(x)}+sum_{yin son(fa(x))|y e x}f_yend{aligned} ]

    用树形DP求出 (f,g),用LCA求出距离。

    代码:

    void dfs (int u, int fa)
    {
    	for (int i = head[u]; i; i = next[i])
    		deg[u]++;
    	ff[u] = deg[u];
    	for (int i = head[u]; i; i = next[i])
    	{
    		int v = to[i];
    		if (v == fa) continue;
    		dfs(v, u);
    		ff[u] += ff[v];
    		ff[u] %= mod;
    	}
    }
    
    void dfs1 (int u, int fa)
    {
    	int sum = deg[u];
    	for (int i = head[u]; i; i = next[i])
    	{
    		int v = to[i];
    		if(v == fa) {sum += g[u];sum%=mod;continue;} 
    		sum += ff[v];
    		sum %= mod;
    	}
    	for (int i = head[u]; i; i = next[i])
    	{
    		int v = to[i];
    		if(v == fa) continue;
    		g[v] = ((sum - ff[v]) % mod + mod) % mod;
    		dfs1(v, u);
    	}
    } 
    
    void dfs2 (int u, int fa)
    {
    	d[u] = d[fa] + 1; 
    	f[u][0] = fa;
    	for (int i = head[u]; i; i = next[i])
    	{
    		int v = to[i];
    		if(v == fa) continue;
    		ff[v] += ff[u];
    		ff[v] %= mod;
    		g[v] += g[u];
    		g[v] %= mod;
    		dfs2 (v, u);
    	}
    }
    
    int lca (int x, int y)
    {
    	if (d[x] > d[y])
    	{
    		int t = x;
    		x = y;
    		y = t;
    	}
    	for (int i = num; i >= 0; i--)
    		if (d[f[y][i]] >= d[x])
    			y = f[y][i];
    	if (x == y) return x;
    	for (int i = num; i >= 0; i--)
    		if (f[x][i] != f[y][i])
    		{
    			x = f[x][i];
    			y = f[y][i];
    		}
    	return f[x][0];
    }
    
    int main()
    {
    	scanf ("%d%d", &n, &m);
    	num = (int) (log2(n)) + 1;
    	for (int i = 1; i < n; i++)
    	{
    		int u, v;
    		scanf ("%d%d", &u, &v);
    		Add(u, v), Add(v, u);
    	}
    	dfs(1, 0);
    	dfs1(1, 0);
    	dfs2(1, 0);
        for (int i = 1; i <= 19; i++)
    	    for (int j = 1; j <= n; j++)
    	 	   f[j][i] = f[f[j][i - 1]][i - 1];
    	for (int i = 1; i <= m; i++)
    	{
    		int a, b;
    		scanf ("%d%d", &a, &b);
    		int LCA = lca(a, b);
    		printf("%d
    ", ((ff[a] - ff[LCA] + g[b] - g[LCA]) % mod + mod) % mod);
    	}
    	return 0;
    }
    
    
  • 相关阅读:
    PHP实现---汉字简体繁体转换
    js对象中的回调函数
    常用js正则
    复合sql
    恢复和去掉所有表约束
    小心as"陷阱"(c#)
    由“js跨域”想到"AJAX也不一定要XMLHttpRequest"
    jsonp与跨域
    关于js的string的3个函数slice,substring,substr对比
    英语etc怎么发音、单词来历
  • 原文地址:https://www.cnblogs.com/GJY-JURUO/p/13472097.html
Copyright © 2020-2023  润新知