树上问题
开题顺序: \(ALFBD\)
\(A\) luogu P2515 [HAOI2010] 软件安装
- 题解
\(B\) CF494D Birthday
-
将式子拆成 \(2\sum\limits_{x \in \operatorname{Subtree}(v)}dis_{u,x}^{2}-\sum\limits_{i=1}^{n}dis_{u,i}^{2}\) 的形式。
-
\(\sum\limits_{i=1}^{n}dis_{u,i}^{2}\) 换根 \(DP\) 加完全平方公式是容易维护的。
-
将前面的式子拆开,有 \(dis_{u,x}^{2}=(dis_{1,x}+dis_{1,u}-2dis_{1,\operatorname{LCA}(u,x)})^{2}=dis_{1,u}^{2}+dis_{1,x}^{2}+4dis_{1,\operatorname{LCA}(u,x)}^{2}+2dis_{1,u}dis_{1,x}-4dis_{1,u}dis_{{1,\operatorname{LCA}(u,x)}}-4dis_{1,x}dis_{{1,\operatorname{LCA}(u,x)}}\) 。
-
将常量 \(u\) 提出去,需要额外处理出 \(\sum\limits_{y \in Subtree(x)}dis_{1,y},\sum\limits_{y \in Subtree(x)}dis_{1,y}^{2}\) 。
-
剩下的部分涉及 \(\operatorname{LCA}\) 的求解,需要进行分讨。
- 当 \(u \notin \operatorname{Subtree}(v)\) 时是容易维护的。
- 当 \(u \in \operatorname{Subtree}(v)\) 时,发现 \(v \to u\) 这条链上的点作为 \(\operatorname{LCA}\) 时难以进行统计答案,需要将式子变形成 \(\sum\limits_{i=1}^{n}dis_{u,i}^{2}-2\sum\limits_{x \notin \operatorname{Subtree}(v)}dis_{u,x}^{2}\) ,然后完全平方公式展开即可。
点击查看代码
const ll p=1000000007; struct node {ll nxt,to,w; }e[200010]; ll head[100010],fa[100010],siz[100010],dep[100010],dis[100010],son[100010],top[100010],f[2][100010],g[2][100010],num[2][100010],n,cnt=0; void add(ll u,ll v,ll w) {cnt++;e[cnt].nxt=head[u];e[cnt].to=v;e[cnt].w=w;head[u]=cnt; } void dfs1(ll x,ll father) {siz[x]=1;fa[x]=father;dep[x]=dep[father]+1;num[0][x]=dis[x];num[1][x]=dis[x]*dis[x]%p;for(ll i=head[x];i!=0;i=e[i].nxt){if(e[i].to!=father){dis[e[i].to]=(dis[x]+e[i].w)%p;dfs1(e[i].to,x);siz[x]+=siz[e[i].to];son[x]=(siz[e[i].to]>siz[son[x]])?e[i].to:son[x];num[0][x]=(num[0][x]+num[0][e[i].to])%p;num[1][x]=(num[1][x]+num[1][e[i].to])%p;f[0][x]=(f[0][x]+f[0][e[i].to]+siz[e[i].to]*e[i].w%p)%p;f[1][x]=(f[1][x]+f[1][e[i].to]+2*e[i].w%p*f[0][e[i].to]%p+e[i].w*e[i].w%p*siz[e[i].to]%p)%p;}} } void dfs2(ll x,ll id) {top[x]=id;for(ll i=head[x];i!=0;i=e[i].nxt){if(e[i].to!=fa[x]){g[0][e[i].to]=(g[0][x]+(n-2*siz[e[i].to]+p)*e[i].w%p)%p;g[1][e[i].to]=(g[1][x]+e[i].w*e[i].w%p*(n-2*siz[e[i].to]+p)%p)%p;g[1][e[i].to]=(g[1][e[i].to]+2*e[i].w%p*((g[0][x]-2*f[0][e[i].to]%p-e[i].w*siz[e[i].to]%p+2*p)%p))%p;dfs2(e[i].to,(e[i].to==son[x])?id:e[i].to);}} } ll lca(ll u,ll v) {while(top[u]!=top[v]){if(dep[top[u]]>dep[top[v]]) u=fa[top[u]];else v=fa[top[v]];}return dep[u]<dep[v]?u:v; } int main() { // #define Isaac #ifdef Isaacfreopen("in.in","r",stdin);freopen("out.out","w",stdout); #endifll m,u,v,w,rt,ans=0,i;cin>>n;for(i=1;i<=n-1;i++){cin>>u>>v>>w;add(u,v,w); add(v,u,w);}dfs1(1,0);g[0][1]=f[0][1]; g[1][1]=f[1][1];dfs2(1,1);cin>>m;for(i=1;i<=m;i++){cin>>u>>v;rt=lca(u,v);if(rt==v){ w=(dis[u]-dis[v]+p)%p;ans=(g[1][v]-f[1][v]+2*w%p*(g[0][v]-f[0][v]+p)%p+w*w%p*(n-siz[v])%p+p)%p;ans=(g[1][u]-2*ans%p+p)%p;}else{ans=(dis[u]*dis[u]%p*siz[v]%p+num[1][v]+2*dis[u]%p*num[0][v]%p)%p;ans=(ans+4*dis[rt]%p*dis[rt]%p*siz[v]%p)%p;ans=(ans-4*dis[u]%p*dis[rt]%p*siz[v]%p+p)%p;ans=(ans-4*dis[rt]%p*num[0][v]%p+p)%p;ans=(ans*2%p-g[1][u]+p)%p;}cout<<ans<<endl;}return 0; }
\(C\) luogu P4757 [CERC2014] Parades
\(D\) [ARC101E] Ribbons on Tree
-
考虑正难则反,统计不合法的数量。具体地,设 \(F(S)\) 表示断掉 \(S\) 中的边后的方案数,则有 \(\sum\limits_{S \subseteq E}(-1)^{|S|}F(S)\) 即为所求。
-
断掉这些边后原树分成了若干个大小为偶数的连通块,每个连通块内部两两配对,设大小为 \(2siz\) 则其内部的方案数为 \(\prod\limits_{i=1}^{siz}(2siz-1)\) ,记为 \(h_{siz}\) 。
-
不妨统计以 \(x\) 为根的子树内 \(x\) 所在连通块大小为 \(i\) 时子树内部的贡献 \(f_{x,i}\)(包括容斥系数在内)。
-
转移时考虑 \((x,y)\) 这条边是否断掉,分别有 \(\begin{cases} f_{x,i}' \gets -f_{x,i}f_{y,j}h_{j} \\ f'_{x,i+j} \gets f_{x,i}f_{y,j} \end{cases}\) ,需要辅助数组进行转移。
-
最终,有 \(\sum\limits_{i=1}^{n}[i \bmod 2=0] \times f_{1,i}h_{i}\) 即为所求。
点击查看代码
const int p=1000000007; struct node {int nxt,to; }e[10010]; int head[5010],siz[5010],h[5010],f[5010][5010],g[5010],cnt=0; void add(int u,int v) {cnt++;e[cnt].nxt=head[u];e[cnt].to=v;head[u]=cnt; } void dfs(int x,int fa) {siz[x]=1;f[x][1]=1;for(int i=head[x];i!=0;i=e[i].nxt){if(e[i].to!=fa){dfs(e[i].to,x);for(int j=1;j<=siz[x]+siz[e[i].to];j++) g[j]=0;for(int j=1;j<=siz[x];j++){for(int k=1;k<=siz[e[i].to];k++){g[j+k]=(g[j+k]+1ll*f[x][j]*f[e[i].to][k]%p)%p;g[j]=(g[j]-1ll*f[x][j]*f[e[i].to][k]%p*h[k]%p+p)%p;}}siz[x]+=siz[e[i].to];for(int j=1;j<=siz[x];j++) f[x][j]=g[j];}} } int main() { // #define Isaac #ifdef Isaacfreopen("in.in","r",stdin);freopen("out.out","w",stdout); #endifint n,u,v,ans=0,i;cin>>n;h[0]=1;for(i=2;i<=n;i++){cin>>u>>v;add(u,v); add(v,u);if(i%2==0) h[i]=1ll*h[i-2]*(i-1)%p;}dfs(1,0);for(i=2;i<=n;i+=2) ans=(ans+1ll*f[1][i]*h[i]%p)%p;cout<<ans<<endl;return 0; }
\(E\) luogu P3748 [六省联考 2017] 摧毁“树状图”
\(F\) luogu P2305 [NOI2014] 购票
- 题解
\(G\) luogu P10805 [CEOI2024] 加油站
\(H\) luogu P4220 [WC2018] 通道
\(I\) LibreOJ 3661. 「2021 集训队互测」蜘蛛爬树
\(J\) luogu P5642 人造情感(emotion)
\(K\) luogu P6830 [IOI2020] 连接擎天树
\(L\) LibreOJ 6669.Nauuo and Binary Tree
- 题解