题面戳我

题意:给一棵树,树上有点权,每次操作为修改一个点的点权,或者是询问以某个点为根时,每棵子树(以每个点为根,就有n棵子树)点权和的平方和。

\(n\le2*10^5\),保证答案在long long范围内

sol

我们设\(s_i\)表示以\(p\)为整棵树的根时,以\(i\)为根的子树的点权和。设\(Sum\)表示所有点的点权和,即\(Sum=\sum_{i=1}^{n}val_i\)。

所以这道题给出\(p\),就是要你求\(\sum_{i=1}^{n}s_i^2\)。

我们先看\(\sum_{i=1}^{n}s_i\)怎么求。

考虑每个点的点权对\(\sum_{i=1}^{n}s_i\)的贡献,可以发现,每个点被计算了\(dep_i+1\)次,也就是说\(\sum_{i=1}^{n}s_i=\sum_{i=1}^{n}val_i(dep_i+1)=\sum_{i=1}^{n}val_idep_i+Sum\)。前面那一坨是不是有点熟悉?【ZJOI2015】幻想乡战略游戏

下文中为了方便描述,令\(calc(p)\)表示以\(p\)为根时的\(\sum_{i=1}^{n}val_idep_i\)

接下来我们考虑一下这个东西

\[\sum_{i=1}^{n}\sum_{j=1}^{n}val_ival_jdis(i,j)
\]

这个可以形象地理解为,在每一对点对\((i,j)\)的路径上每一条边(刚好是\(dis(i,j)\)条边)上都加上\(val_ival_j\),然后求整棵树上的边权之和。

现在我们考虑每一条边上的权值,它应该等于它两侧连接的两坨树的点权和的乘积。而连接的这两坨树中,不论取哪个\(p\)为根,都有有且仅有一坨树会是一棵子树。所以这个权值会等于\(s_i(Sum-s_i)\)。所以

\[\sum_{i=1}^{n}\sum_{j=1}^{n}val_ival_jdis(i,j)=\sum_{i=1}^{n}s_i(Sum-s_i)
\]

这同时也证明了不论取哪个\(p\)作为根,\(\sum_{i=1}^{n}s_i(Sum-s_i)\)都不会变。

令\(W=\sum_{i=1}^{n}s_i(Sum-s_i)\),可以先\(O(n)\)地\(DP\)出\(W\)的初值,然后就只要考虑一个点权修改对\(W\)的影响。

因为\(W=\sum_{i=1}^{n}\sum_{j=1}^{n}val_ival_jdis(i,j)\),若节点\(i\)的点权的变化量为\(\Delta v\),那么\(\Delta W=\Delta v\sum_{j=1}^{n}val_jdis(i,j)\),相当于\(\Delta v*calc(i)\),所以说一样地计算即可。

所以最终询问的答案就是:

\[\sum_{i=1}^{n}s_i^2=Sum*\sum_{i=1}^{n}s_i-W=Sum(calc(i)+Sum)-W
\]

code

#include<cstdio>
#include<algorithm>
using namespace std;
#define ll long long
const int N = 200005;
int gi()
{
int x=0,w=1;char ch=getchar();
while ((ch<'0'||ch>'9')&&ch!='-') ch=getchar();
if (ch=='-') w=0,ch=getchar();
while (ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
return w?x:-x;
}
struct edge{int to,next;}a[N<<1];
int n,q,val[N],head[N],cnt,pa[N],dep[N],sz[N],son[N],top[N];
void dfs1(int u,int f)
{
pa[u]=f;dep[u]=dep[f]+1;sz[u]=1;
for (int e=head[u];e;e=a[e].next)
{
int v=a[e].to;if (v==f) continue;
dfs1(v,u);
sz[u]+=sz[v];if (sz[v]>sz[son[u]]) son[u]=v;
}
}
void dfs2(int u,int f)
{
top[u]=f;
if (son[u]) dfs2(son[u],f);else return;
for (int e=head[u];e;e=a[e].next)
if (a[e].to!=pa[u]&&a[e].to!=son[u])
dfs2(a[e].to,a[e].to);
}
int lca(int u,int v)
{
while (top[u]^top[v])
{
if (dep[top[u]]<dep[top[v]]) swap(u,v);
u=pa[top[u]];
}
return dep[u]<dep[v]?u:v;
}
int getdis(int u,int v){return dep[u]+dep[v]-(dep[lca(u,v)]<<1);}
int tot,root,vis[N],w[N],fa[N];
ll sum[N],gather[N],tofa[N],sigma,omega,ans;
void getroot(int u,int f)
{
sz[u]=1;w[u]=0;
for (int e=head[u];e;e=a[e].next)
{
int v=a[e].to;if (v==f||vis[v]) continue;
getroot(v,u);
sz[u]+=sz[v];w[u]=max(w[u],sz[v]);
}
w[u]=max(w[u],tot-sz[u]);
if (w[u]<w[root]) root=u;
}
void solve(int u,int f)
{
fa[u]=f;vis[u]=1;
for (int e=head[u];e;e=a[e].next)
{
int v=a[e].to;if (vis[v]) continue;
tot=sz[v];
root=0;
getroot(v,0);
solve(root,u);
}
}
void modify(int u,int v)
{
sum[u]+=v;
for (int i=u;fa[i];i=fa[i])
{
int dist=getdis(u,fa[i]);
sum[fa[i]]+=v;
gather[fa[i]]+=dist*v;
tofa[i]+=dist*v;
}
}
ll calc(int u)
{
ll res=gather[u];
for (int i=u;fa[i];i=fa[i])
{
int dist=getdis(u,fa[i]);
res+=(ll)dist*(sum[fa[i]]-sum[i]);
res+=gather[fa[i]]-tofa[i];
}
return res;
}
void DP(int u)
{
sz[u]=val[u];
for (int e=head[u];e;e=a[e].next)
{
int v=a[e].to;if (v==pa[u]) continue;
DP(v);sz[u]+=sz[v];
}
omega+=1ll*sz[u]*(sigma-sz[u]);
}
int main()
{
n=gi();q=gi();
for (int i=1;i<n;i++)
{
int u=gi(),v=gi();
a[++cnt]=(edge){v,head[u]};head[u]=cnt;
a[++cnt]=(edge){u,head[v]};head[v]=cnt;
}
dfs1(1,0);dfs2(1,1);
tot=w[0]=n;
getroot(1,0);
solve(root,0);
for (int i=1;i<=n;i++)
val[i]=gi(),modify(i,val[i]),sigma+=val[i];
DP(1);
while (q--)
{
int opt=gi(),x=gi();
if (opt==1)
{
int y=gi();
modify(x,y-val[x]);sigma+=y-val[x];
omega+=(y-val[x])*calc(x);
val[x]=y;
}
else printf("%lld\n",(calc(x)+sigma)*sigma-omega);
}
return 0;
}

[Luogu3676]小清新数据结构题的更多相关文章

  1. [luogu3676] 小清新数据结构题 [树链剖分+线段树]

    题面 传送门 思路 本来以为这道题可以LCT维护子树信息直接做的,后来发现这样会因为splay形态改变影响子树权值平方和,是splay本身的局限性导致的 所以只能另辟蹊径 首先,我们考虑询问点都在1的 ...

  2. Luogu3676 小清新数据结构题 动态点分治

    传送门 换根类型的统计问题动态点分治都是很好做的. 设所有点的点权和为$sum$ 首先,我们先不考虑求$\sum\limits_i s_i^2$,先考虑如何在换根的情况下求$\sum\limits_i ...

  3. Luogu3676 小清新数据结构题(树链剖分+线段树)

    先不考虑换根.考虑修改某个点权值对答案的影响.显然这只会改变其祖先的子树权值和,设某祖先原子树权值和为s,修改后权值增加了x,则对答案的影响为(s+x)2-s2=2sx+x2.可以发现只要维护每个点到 ...

  4. 【Luogu3676】小清新数据结构题(动态点分治)

    [Luogu3676]小清新数据结构题(动态点分治) 题面 洛谷 题解 先扯远点,这题我第一次看的时候觉得是一个树链剖分+线段树维护. 做法大概是这样: 我们先以任意一个点为根,把当前点看成是一棵有根 ...

  5. [P3676]小清新数据结构题

    Description: 给你一棵树,每次询问以一个点为根时所有子树点权和的平方和 带修改 Hint: \(n\le 2*10^5\) Solution: 这题只要推出式子就很简单了 如果不换根这个平 ...

  6. 洛谷P3676 小清新数据结构题(动态点分治+树链剖分)

    传送门 感觉这题做下来心态有点崩……$RMQ$求$LCA$没有树剖快我可以理解为是常数太大……然而我明明用了自以为不会退化的点分然而为什么比会退化的点分跑得反而更慢啊啊啊啊~~~ 先膜一波zsy大佬 ...

  7. 洛谷 P3676 小清新数据结构题

    https://www.luogu.org/problemnew/show/P3676 这题被我当成动态dp去做了,码了4k,搞了一个换根的动态dp #include<cstdio> #i ...

  8. 洛谷 P3676 - 小清新数据结构题(动态点分治)

    洛谷题面传送门 题目名称好评(实在是太清新了呢) 首先考虑探究这个"换根操作"有什么性质.我们考虑在换根前后虽然每个点的子树会变,但整棵树的形态不会边,换句话说,割掉每条边后,得到 ...

  9. 洛谷P3676 小清新数据结构题 [动态点分治]

    传送门 思路 这思路好妙啊! 首先很多人都会想到推式子之后树链剖分+线段树,但这样不够优美,不喜欢. 脑洞大开想到这样一个式子: \[ \sum_{x} sum_x(All-sum_x) \] 其中\ ...

随机推荐

  1. 阿里云学习之IOT物联网套件(配置篇)

    文档时间:2018.-1-24 首注:此文章是参照以下文章的整合与补充: https://bbs.aliyun.com/read/309106.html?amp;displayMode=1&p ...

  2. Python数据分析学习-re正则表达式模块

    正则表达式 为高级的文本模式匹配.抽取.与/或文本形式的搜索和替换功能提供了基础.简单地说,正则表达式(简称为 regex)是一些由字符和特殊符号组成的字符串,它们描述了模式的重复或者表述多个字符,于 ...

  3. shell 脚本中执行SQL语句 -e "..."

    /usr/local/mysql/bin/mysql -uroot -p123456 -e " use faygo source faygo.sql select * from devqui ...

  4. chrome下input文本框自动填充背景问题解决

    chrome下input文本框会自动填充背景,只需要给文本框加一个样式即可解决问题 input:-webkit-autofill {-webkit-box-shadow: 0 0 0px 1000px ...

  5. Linux一些常用操作

    1.linux swap分区 可采用文件的方式 dd if=/dev/zero of=/var/swap bs=1024 count=2048000 mkswap /var/swap swapon / ...

  6. HashMap原理阅读

    前言 还是需要从头阅读下HashMap的源码.目标在于更好的理解HashMap的用法,学习更精炼的编码规范,以及应对面试. 它根据键的hashCode值存储数据,大多数情况下可以直接定位到它的值,因而 ...

  7. IE兼容swiper

    swiper3能完美运用在移动端,但是运用在PC端,特别是IE浏览器上不能兼容,没有效果,要使IE兼容Swiper的话必须使用swiper2,也就是idangerous.swiper.js, 下载地址 ...

  8. ubuntu16.04 python3 安装selenium及环境配置

    环境 ubuntu16.04 python3 安装selenium sudo pip3 install seleium 默认安装完是支持firefox,但是更新得太慢对于较新的firefox已经不支持 ...

  9. A.Alyona and copybooks

    这题考查思维的全面性. 一开始我直接分类推公式,余数不同分类讨论. AC代码: #include<cstdio> #include<algorithm> using names ...

  10. 对于JAVA程序优化的一些想法,读书有感.治疗强迫症良药

    在深入了解Java虚拟机里读到:在try{}块里面执行代码,比if(x!=null)效率要高,前提是被catch的几率很低的情况下. 但是 在Effective Java里读到:因为异常机制的设计初衷 ...