zoukankan      html  css  js  c++  java
  • Sky 要上树

    看到这个式子,显然是个计数问题。要考虑这条链上每条边的贡献次数。这时候不妨暴力打一下,出个表。比如下面这个
    1 1 2 4 8
    1 3 8 20
    2 8 26
    4 20
    8

    第i行第j列表示长度为i+j-1的链上第j边会被计算多少次。

    很容易发现

    [V(i,j)= frac{sum_{x le i,y le j,且(x,y) eq (i,j)}^{}V(x,y) }{2} ]

    不会证明,但是很容易发现。。

    然后这就是个很简单的计数问题了。因为n很小,每次询问可以暴力跳lca,把每条边贡献都算出来
    时间复杂度(O(n^2+qn))

    
    #include<bits/stdc++.h>
    #define rep(i,j,k) for(register int i(j);i<=k;++i)
    #define drp(i,j,k) for(register int i(j);i>=k;--i)
    using namespace std;
    typedef long long lxl;
    template<typename T>
    inline T  max(T &a, T &b) {
    	return a > b ? a : b;
    }
    template<typename T>
    inline T  min(T &a, T &b) {
    	return a < b ? a : b;
    }
    inline char gt() {
    	static char buf[1 << 21], *p1 = buf, *p2 = buf;
    	return p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 1 << 21, stdin), p1 == p2) ? EOF : *p1++;
    }
    template <typename T>
    inline void  read(T &x) {
    	register char ch = gt();
    	x = 0;
    	int w(0);
    	while(!(ch >= '0' && ch <= '9'))w |= ch == '-', ch = gt();
    	while(ch >= '0' && ch <= '9')x = x * 10 + (ch & 15), ch = gt();
    	w ? x = ~(x - 1) : x;
    }
    template <typename T>
    inline void out(T x) {
    	if(x < 0) x = -x, putchar('-');
    	char ch[20];
    	int num(0);
    	while(x || !num) ch[++num] = x % 10 + '0', x /= 10;
    	while(num) putchar(ch[num--]);
    	putchar('
    ');
    }
    
    const int MX = 2e3 + 79;
    const int mod = 1e9 + 7;
    struct graph {
    	int next[MX << 1], head[MX], tot, ver[MX << 1], edge[MX << 1];
    	inline void add(int a, int b, int c) {
    		ver[++tot] = b;
    		next[tot] = head[a];
    		edge[tot] = c;
    		head[a] = tot;
    	}
    } G;
    int n, dep[MX << 1], fa[MX << 1], dis[MX << 1];
    inline void dfs(int x) {
    	for(register int i(G.head[x]); i; i = G.next[i]) {
    		int y = G.ver[i], z = G.edge[i];
    		if(y == fa[x]) continue;
    		dep[y] = dep[x] + 1;
    		dis[y] = z;
    		fa[y] = x;
    		dfs(y);
    	}
    }
    inline int LCA(int x, int y) {
    	if(dep[x] < dep[y]) swap(x, y);
    	while(dep[x] != dep[y]) x = fa[x];
    	while(x != y) x = fa[x], y = fa[y];
    	return x;
    }
    int val[MX][MX], sum[MX][MX];
    
    
    int main() {
    	freopen("tree.in", "r", stdin);
    	freopen("tree.out", "w", stdout);
    	read(n);
    	int u, v, w;
    	rep(i, 2, n) {
    		read(u);
    		read(v);
    		read(w);
    		G.add(u, v, w);
    		G.add(v, u, w);
    	}
    	dfs(1);
    	val[1][1] = sum[1][1] = 1;
    	rep(i, 1, n)
    	rep(j, 1, n) {
    		val[i][j] += (1ll * sum[i - 1][j] + sum[i][j - 1] - sum[i - 1][j - 1] + mod) % mod;
    		sum[i][j] += 2ll * (1ll * sum[i - 1][j] + sum[i][j - 1] - sum[i - 1][j - 1] + mod) % mod;
    	}
    	int q;read(q);
    	while(q--){
    		read(u);read(v);
    		int lca=LCA(u,v);
    		int ans(0);
    		if(lca==u||lca==v){
    			if(dep[u]>dep[v]) swap(u,v);
    			int len=dep[v]-dep[u],i=1;
    			while(u!=v){
    				ans+=1ll*dis[v]*val[i][len-i+1]%mod;
    				if(ans>=mod) ans-=mod;
    				++i;
    				v=fa[v];
    			}
    		}
    		else{
    			int len=dep[v]+dep[u]-2*dep[lca],i=1;
    			while(u!=lca){
    				ans+=1ll*dis[u]*val[i][len-i+1]%mod;
    				if(ans>=mod) ans-=mod;
    				++i;
    				u=fa[u];
    			}
    			i=1;
    			while(v != lca) {
    				ans += 1LL * dis[v] * val[i][len - i + 1] % mod;
    				if(ans >= mod) ans -= mod;
    				++ i;
    				v = fa[v];
    			}
    		}
    		out(ans);
    	}
    	return 0;
    }
    

    本文来自博客园,作者:{2519},转载请注明原文链接:https://www.cnblogs.com/QQ2519/p/15120803.html

  • 相关阅读:
    VirtualBox的四种网络连接方式详解
    need to be root
    Unreachable catch block for IOException. This exception is never thrown from the try statement body
    git fetch 拉取而不合并
    IOS开发的哪些异常之异常断点
    duplicate报ORA-01017权限问题
    Woody的Python学习笔记4
    微软100题第51题:和为n连续正数序列
    C语言scanf函数详解
    火星人乘坐核动力飞船回故乡
  • 原文地址:https://www.cnblogs.com/QQ2519/p/15120803.html
Copyright © 2011-2022 走看看