题解 单

· · 个人记录

T2 单

解题思路

看遍网上题解都说是个高级的 换根DP 感觉有一点关系,但不知道也无妨。

先看暴力

暴力思路比较好像,对于t=1的情况直接Dij或者LCA,DFS也行;t=2的式子一看就可以高斯消元,要注意的就是卡一下精度,开double,输出的时候手动四舍五入或者加上一个1e-12也可以输出整数位,但是绝不能int强制转化!!!

code

再看正解

sum[i]表示以 i 为根的子树的 a 之和。

t=0

可以得出式子:b[now]=(b[fa]-sum[now])+(sum[1]-sum[now])

以下图为例

假设now=6,那么 fa=4,将数值由fa转移到now

此时我们把整棵树划分为两部分:

现在,式子的前半部分就是fa的b减去now子树部分的a,这就是now子树对于b[now]的贡献以及B部分的部分贡献,相比于fa,now相较于B的深度多一,因此要加上sum[1]-sum[now]。这一块的式子很妙,可以多思考一下。

然后进行 DFS 求出 sum 数组,进而求出 b 数组就好了。

t=1

和t=1的式子有一定的关系,移一下项:

b[now]-b[fa]=sum[1]-sum[now]

求一下和:

\sum\limits_{i=2}^nb[i]+b[fa(i)]=sum[1]\times(n-1)-2\times\sum\limits_{i=2}^nsum[i]

也就是:

x_1b[1]+x_2b[2]+...+x_nb[n]=(n-1)sum[1]-2\times\sum\limits_{i=2}^nsum[now]

与前面的换根的思路相似,不难发现2\times\sum\limits_{i=2}^nsum[now]其实就是b[1],在此不做过多赘述。

然后进行DFS求出每个系数x,然后就可以求出sum[1]

再进行DFS求一下其他的sum。

然后再再进行DFS求出整棵树的a就好了。 ## code ```cpp #include<bits/stdc++.h> #define int long long //#define double long double using namespace std; const int N=1e5+10,M=1e4+10; int T,n; int dis[N],sum[N],s[N]; int tot,T_temp,head[N],nxt[N<<1],ver[N<<1],a[N],b[N]; inline void add_edge(int x,int y) { ver[++tot]=y; nxt[tot]=head[x]; head[x]=tot; } void dfs(int x,int fa,int dep) { b[1]+=a[x]*dep; for(int i=head[x];i;i=nxt[i]) { int to=ver[i]; if(to==fa) continue; dfs(to,x,dep+1); } } void dfs1(int x,int fa) { for(int i=head[x];i;i=nxt[i]) { int to=ver[i]; if(to==fa) continue; dfs1(to,x); sum[x]+=sum[to]; } sum[x]+=a[x]; } void dfs2(int x,int fa) { b[x]=b[fa]+sum[1]-2*sum[x]; for(int i=head[x];i;i=nxt[i]) { int to=ver[i]; if(to==fa) continue; dfs2(to,x); } } inline void work_B() { dfs(1,0,0); dfs1(1,0); for(int i=head[1];i;i=nxt[i]) dfs2(ver[i],1); for(int i=1;i<=n;i++) printf("%lld ",b[i]); printf("\n"); } void dfs3(int x,int fa) { s[x]++; s[fa]--; for(int i=head[x];i;i=nxt[i]) { int to=ver[i]; if(to==fa) continue; dfs3(to,x); } } void dfs4(int x,int fa) { sum[x]=(b[fa]-b[x]+sum[1])/2; for(int i=head[x];i;i=nxt[i]) { int to=ver[i]; if(to==fa) continue; dfs4(to,x); } } void dfs5(int x,int fa) { int temp=sum[x]; for(int i=head[x];i;i=nxt[i]) { int to=ver[i]; if(to==fa) continue; dfs5(to,x); temp-=sum[to]; } a[x]=temp; } inline void work_A() { memset(s,0,sizeof(s)); int temp=0; for(int i=head[1];i;i=nxt[i]) dfs3(ver[i],1); for(int i=1;i<=n;i++) temp+=s[i]*b[i]; sum[1]=(temp+2*b[1])/(n-1); for(int i=head[1];i;i=nxt[i]) dfs4(ver[i],1); dfs5(1,0); for(int i=1;i<=n;i++) printf("%lld ",a[i]); printf("\n"); } inline void work() { tot=0; memset(ver,0,sizeof(ver)); memset(head,0,sizeof(head)); memset(nxt,0,sizeof(nxt)); memset(sum,0,sizeof(sum)); scanf("%lld",&n); for(int i=1,x,y;i<n;i++) { scanf("%lld%lld",&x,&y); add_edge(x,y); add_edge(y,x); } scanf("%lld",&T_temp); if(T_temp) { memset(a,0,sizeof(a)); for(int i=1;i<=n;i++) scanf("%lld",&b[i]); work_A(); } else { memset(b,0,sizeof(b)); for(int i=1;i<=n;i++) scanf("%lld",&a[i]); work_B(); } } #undef int int main() { #define int register long long #define ll long long scanf("%lld",&T); while(T--) work(); return 0; } ```