标签:情况 blank scan 高斯消元 sum eof 成绩 高斯 color
liu_runda出的题,先%%%%%%%%%%%为敬
考试时只打了一个普通$n^2$暴力,然后$gauss$开的$long long$出现精度问题得了$0$分的好成绩
$10\%$算法
暴力过$t==0$
$40\%$算法
gauss+暴力过前几个点
$100\%$算法
先算$t==0$
看$n^2$问题出现在那
重复计算多次距离,我们可以想个方法把自己的已经算过的存起来
现在假设我们有这样一棵树(1,2,3……代表点权,(为了方便)也代表编号)
看2 和4 的关系
子树内所有的点权值贡献$-1$,子树外所有点权贡献$+1$
事实上我们可以把我们计算过的存起来。用一个前缀和思想,把子树的和算出来,我们得到1的b就可以通过$b+ -$得到$2$的$b$
那么我们只需要一次dfs处理出所有子树权值和就可以得出来所有b
式子$b[y]=b[x]-sum[y]+sum[1]-sum[y]$
这一点思想莫名像莫队,自从学了莫队我就觉得什么都是莫队
寿司这个题我就用了类似莫队思想,求出来一个$ans$然后通过$ans+-$,得到另一个$ans$
(我也颓了题解)
再看t==1的情况
看上去只能高斯消元,对吗?
实际上我们可以换种思路考虑
将$b[y]=b[x]-sum[y]+sum[1]-sum[y]$移项
得到$sum[1]-2\times sum[y]= b[y]-b[x]$
设dt数组表示两个sum之差dt[y]=b[y]-b[x]
我们可以用一次dfs求出dt那么,我们差的就只剩下sum[1] sum[y]了
仍然没法做对吗?
sum[1]其实可以求
假设1为根
$b[1]=\sum\limits_{i=2}^{n} sum[i]$
感性理解+手膜
还是这个图
每次都是路径长度$\times$权值,计算$2$的时候算了一遍$4 8 9$,计算4时又算了一遍$8 9$,路径每一个点上会被计算它到根节点之间节点个数(其实就是边数),所以最终得到的就是b[1]
同样,我们处理出来dt,再通过一次dfs求sum,然后最后dfs一次就好了
#include<bits/stdc++.h> using namespace std; #define mem(x) memset(x,0,sizeof(x)) #define ll long long #define A 1100000 ll head[A],nxt[A],ver[A],a[A],b[A],sum[A],f[A],dt[A]; ll tot=0,n,t,xx,yy,task; void add(ll x,ll y){ nxt[++tot]=head[x],head[x]=tot,ver[tot]=y; } void re(){ tot=0; mem(head); mem(nxt); mem(ver); mem(sum); mem(dt); mem(b); mem(f); mem(a); } void dfs1(ll x,ll fa){ sum[x]=a[x]; for(ll i=head[x];i;i=nxt[i]){ ll y=ver[i]; if(y==fa) continue; f[y]=x; dfs1(y,x); sum[x]+=sum[y]; } } void dfs0(ll x,ll fa){ for(ll i=head[x];i;i=nxt[i]){ ll y=ver[i]; if(y==fa) continue; b[y]=b[x]+sum[1]-2*sum[y]; dfs0(y,x); } } void work1(){ dfs1(1,0); for(ll i=2;i<=n;i++){ b[1]+=sum[i]; } dfs0(1,0); for(ll i=1;i<=n;i++){ printf("%lld ",b[i]); } printf("\n"); } void dfs2(ll x,ll fa){ for(ll i=head[x];i;i=nxt[i]){ ll y=ver[i]; if(y==fa) continue; dfs2(y,x); // printf("b[]=%lld %lld\n",b[y],b[x]); dt[y]=b[y]-b[x]; } } void dfs3(ll x,ll fa){ for(ll i=head[x];i;i=nxt[i]){ ll y=ver[i]; if(y==fa) continue; dfs3(y,x); sum[y]=(sum[1]-dt[y])/2; } } void dfs4(ll x,ll fa){ a[x]=sum[x]; for(ll i=head[x];i;i=nxt[i]){ ll y=ver[i]; if(y==fa) continue; dfs4(y,x); a[x]-=sum[y]; } } void work2(){ dt[1]=0; ll zt=0; dfs2(1,0); for(ll i=2;i<=n;i++) zt+=dt[i]; sum[1]=(zt+2*b[1])/(n-1); // printf("sum1=%lld\n",sum[1]); dfs3(1,0); dfs4(1,0); for(ll i=1;i<=n;i++){ printf("%lld ",a[i]); } printf("\n"); } int main(){ scanf("%lld",&t); while(t--){ re(); scanf("%lld",&n); for(ll i=1;i<n;i++){ scanf("%lld%lld",&xx,&yy); add(xx,yy),add(yy,xx); } scanf("%lld",&task); task++; if(task==1){ for(ll i=1;i<=n;i++){ scanf("%lld",&a[i]); } work1(); } else{ for(ll i=1;i<=n;i++){ scanf("%lld",&b[i]); } work2(); } } }
标签:情况 blank scan 高斯消元 sum eof 成绩 高斯 color
原文地址:https://www.cnblogs.com/znsbc-13/p/11257689.html