题意:给一棵带边权的树,定义如下的一些东西

$S(x)$表示以$x$为根的子树中的节点组成的集合

$d(u,v)$表示$u$和$v$之间的距离

$f(u,v)\sum\limits_{x\in S(v)}d(u,x)^2-\sum\limits_{x\notin S(v)}d(u,x)^2$

多次询问求$f(u,v)$的值,对$10^9+7$取模至非负数

非常妙的树D!这个题啊,excited!

首先它涉及到了子树,我们当然要先dfs一次求出$dsum_i=\sum\limits_{x\in S(i)}d(i,x)$,$dsum2_i=\sum\limits_{x\in S(i)}d(i,x)^2$,子树大小$siz_i$和每个节点到根的距离$dis_i$

这个转移比较简单,设$son(x)$表示$x$的儿子组成的集合

考虑从$son(i)$转移到$i$,(以下均有$x\in son(i)$)

$\begin{align*}dsum_i&=\sum\limits_{x\in S(i),x\ne i}d(x,i)\\&=\sum\limits_{x\in S(i),x\ne i}d(x,k)+d(k,i)\\&=\sum\limits_{k\in son(i)}\left(dsum_k+siz_k\cdot d(k,i)\right)\end{align*}$

$\begin{align*}dsum2_i&=\sum\limits_{x\in S(i),x\ne i}d(i,x)^2\\&=\sum\limits_{x\in S(i),x\ne i}(d(x,k)+d(k,i))^2\\&=\sum\limits_{x\in S(i),x\ne i}(d(x,k)^2+2\cdot d(x,k)\cdot d(k,i)+d(k,i)^2)\\&=\sum\limits_{k\in son(i)}\left(dsum2_k+2\cdot d(k,i)\cdot dsum_k+siz_k\cdot d(k,i)^2\right)\end{align*}$

下一步,因为询问涉及到全局,所以我们要再dfs一次求出$alld_i=\sum\limits_{1\leq j\leq n}d(i,j)$,$alld2_i=\sum\limits_{1\leq j\leq n}d(i,j)^2$

因为题目钦定了说明了$1$是根,所以$alld_1=dsum_1,alld2_1=dsum2_1$

考虑从$i$转移到$son(i)$,(以下均有$x\in son(i)$)

$\begin{align*}alld_x&=\sum\limits_{j\in S(x)}d(x,j)+\sum\limits_{j\notin S(x)}d(x,j)\\&=\sum\limits_{j\in S(x)}\left(d(i,j)-d(x,i)\right)+\sum\limits_{j\notin S(x)}\left(d(i,j)+d(x,i)\right)\\&=alld_i-siz_x\cdot d(x,i)+(n-siz_x)\cdot d(x,i)\\&=alld_i+(n-2\cdot siz_x)\cdot d(x,i)\end{align*}$

$\begin{align*}alld2_x&=\sum\limits_{j\in S(x)}d(x,j)^2+\sum\limits_{j\notin S(x)}d(x,j)^2\\&=\sum\limits_{j\in S(x)}(d(i,j)-d(x,i))^2+\sum\limits_{j\notin S(x)}(d(i,j)+d(x,i))^2\\&=\sum\limits_{j\in S(x)}(d(i,j)^2-2\cdot d(i,j)\cdot d(x,i)+d(x,i)^2)+\sum\limits_{j\notin S(x)}(d(i,j)^2+2\cdot d(i,j)\cdot d(x,i)+d(x,i)^2)\\&=alld2_i-2\cdot d(x,i)\cdot(\sum\limits_{j\in S(x)}d(i,j)-\sum\limits_{j\notin S(x)}d(i,j))+n\cdot d(x,i)^2\\&=alld2_i+n\cdot d(x,i)^2-2\cdot d(x,i)\cdot(\sum\limits_{j\in S(x)}d(i,j)-(alld_i-\sum\limits_{j\in S(x)}d(i,j)))\\&=alld2_i+n\cdot d(x,i)^2-2\cdot d(x,i)\cdot(2(dsum_x+siz_x\cdot d(x,i))-alld_i)\end{align*}$

预处理出这些东西之后,看一看如何计算答案

首先当然要求一下lca,直接上倍增

#1若$u\notin S(v)$($lca(u,v)\ne v$)

$\sum\limits_{x\notin S(v)}d(u,x)^2=alld2_u-\sum\limits_{x\in S(v)}d(u,x)^2$

$\begin{align*}\sum\limits_{x\in S(v)}d(u,x)^2&=\sum\limits_{x\in S(v)}(d(u,v)+d(v,x))^2\\&=siz_v\cdot d(u,v)^2+2\cdot d(u,v)\cdot\sum\limits_{x\in S(v)}d(v,x)+\sum\limits_{x\in S(v)}d(v,x)^2\\&=siz_v\cdot d(u,v)^2+2\cdot d(u,v)\cdot dsum_v+dsum2_v\end{align*}$

#2若$u\in S(v)$($lca(u,v)=v$)

$\begin{align*}\sum\limits_{x\notin S(v)}d(u,x)^2&=\sum\limits_{x\notin S(v)}(d(u,v)+d(v,x))^2\\&=(n-siz_v)\cdot d(u,v)^2+2\cdot d(u,v)\cdot\sum\limits_{x\notin S(v)}d(v,x)+\sum\limits_{x\notin S(v)}d(v,x)^2\\&=(n-siz_v)\cdot d(u,v)^2+2\cdot d(u,v)\cdot(alld_v-dsum_v)+alld2_v-dsum2_v\end{align*}$

然后就ok啦,写转移真是烧脑啊

#include<stdio.h>
#define mod 1000000007ll
#define ll long long
ll mo(ll x){return x%mod;}
struct edge{
	int to,nex;
	ll v;
}e[200010];
ll dsum[100010],dsum2[100010],alld[100010],alld2[100010],siz[100010],dis[100010];
int h[100010],fa[100010][17],dep[100010],tot,n;
void add(int a,int b,ll c){
	tot++;
	e[tot].to=b;
	e[tot].v=c;
	e[tot].nex=h[a];
	h[a]=tot;
}
void dfs(int x){
	siz[x]=1;
	for(int i=h[x];i;i=e[i].nex){
		if(e[i].to!=fa[x][0]){
			dis[e[i].to]=mo(dis[x]+e[i].v);
			fa[e[i].to][0]=x;
			dep[e[i].to]=dep[x]+1;
			dfs(e[i].to);
			siz[x]+=siz[e[i].to];
			dsum[x]=mo(dsum[x]+dsum[e[i].to]+siz[e[i].to]*e[i].v);
			dsum2[x]=mo(dsum2[x]+mo(e[i].v*e[i].v)*siz[e[i].to]+2ll*e[i].v*dsum[e[i].to]+dsum2[e[i].to]);
		}
	}
}
void dfs2(int x){
	for(int i=h[x];i;i=e[i].nex){
		if(e[i].to!=fa[x][0]){
			alld[e[i].to]=mo(alld[x]+(n-2ll*siz[e[i].to])*e[i].v);
			alld2[e[i].to]=mo(alld2[x]+2ll*e[i].v*mo(alld[x]-2ll*dsum[e[i].to]-siz[e[i].to]*e[i].v)+(n-2ll*siz[e[i].to])*mo(e[i].v*e[i].v));
			dfs2(e[i].to);
		}
	}
}
void swap(int&a,int&b){
	int c=a;
	a=b;
	b=c;
}
int lca(int x,int y){
	if(dep[x]<dep[y])swap(x,y);
	int i;
	for(i=16;i>=0;i--){
		if(dep[fa[x][i]]>=dep[y])x=fa[x][i];
	}
	if(x==y)return x;
	for(i=16;i>=0;i--){
		if(fa[x][i]!=fa[y][i]){
			x=fa[x][i];
			y=fa[y][i];
		}
	}
	return fa[x][0];
}
int main(){
	int q,i,j,u,v,uv;
	ll w;
	scanf("%d",&n);
	for(i=1;i<n;i++){
		scanf("%d%d%I64d",&u,&v,&w);
		add(u,v,w);
		add(v,u,w);
	}
	dep[1]=1;
	dfs(1);
	alld[1]=dsum[1];
	alld2[1]=dsum2[1];
	dfs2(1);
	for(j=1;j<17;j++){
		for(i=1;i<=n;i++)fa[i][j]=fa[fa[i][j-1]][j-1];
	}
	scanf("%d",&q);
	while(q--){
		scanf("%d%d",&u,&v);
		uv=lca(u,v);
		if(uv==v){
			w=mo(dis[u]-dis[v]);
			w=mo((n-siz[v])*mo(w*w)+2ll*w*(alld[v]-dsum[v])+alld2[v]-dsum2[v]);
			w=mo(alld2[u]-2ll*w);
		}else{
			w=mo(dis[u]+dis[v]-2ll*dis[uv]);
			w=mo(siz[v]*mo(w*w)+2ll*w*dsum[v]+dsum2[v]);
			w=mo(2ll*w-alld2[u]);
		}
		printf("%I64d\n",mo(w+mod));
	}
}

[CF494D]Birthday的更多相关文章

随机推荐

  1. MySQL使用笔记(四)数据的操作

    By francis_hao    Dec 14,2016 数据的操作包括插入数据记录.更新数据记录和删除数据记录. 插入数据记录 插入单条数据记录 field表示的字段名和value表示数据要一一对 ...

  2. [hdu 2586]lca模板题(在线+离线两种版本)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2586 在线版本: 在线方法的思路很简单,就是倍增.一遍dfs得到每个节点的父亲,以及每个点的深度.然后 ...

  3. PAT团体程序设计大赛---(模拟)

    L1-1 古风排版(20 分) 中国的古人写文字,是从右向左竖向排版的.本题就请你编写程序,把一段文字按古风排版. 输入格式: 输入在第一行给出一个正整数N(<100),是每一列的字符数.第二行 ...

  4. Python代码规范

    一:背景 用于规范化ocp python开发,对于使用python开发的程序使用统一的风格,便于代码的维护 二:python风格规范 分号:不要在行尾加分号,也不要用分号将两条命令放在同一行 括号:宁 ...

  5. 【洛谷 P4211】[LNOI2014]LCA(树链剖分,差分)

    题目链接 看到题目肯定首先想到要求LCA(其实是我菜),可乍一看,n与q的规模为5W, 求LCA的复杂度为\(O(logN)\),那么总时间复杂度为\(O(nq\ log\ n)\). 怎么搞呢? 会 ...

  6. bzoj 3190 维护栈

    我们可以将每一辆赛车看成一条直线,斜率为速度,纵截距为初始位置,那么问题就转化为求这n条直线处于最上面的直线.最上面是指在坐标系中,假设从x轴向下看,能看到的直线,只露一个点也算能看见.那么就类似水平 ...

  7. 小苏的Shell编程笔记之六--Shell中的函数

    http://xiaosu.blog.51cto.com/2914416/531247 Shell函数类似于Shell脚本,里面存放了一系列的指令,不过Shell的函数存在于内存,而不是硬盘文件,所以 ...

  8. JS实现上下左右对称的九九乘法表

    JS实现上下左右对称的九九乘法表 css样式 <style> table{ table-layout:fixed; border-collapse:collapse; } td{ padd ...

  9. 修改ueditor CSS

  10. Flex slider参数详细

    $(window).load(function() { $('.flexslider').flexslider({ animation: "fade", //String: Sel ...