传送门

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

  先膜一波zsy大佬

  讲讲做法。题目的要求是给定一个根$p$,求$\sum _{i=1}^ns_i^2$,其中$s_i$表示子树中的点权和

  我们设$sum=\sum _{i=1}^n val_i$,即整棵树的点权和。先考虑一下$\sum _{i=1}^ns_i$怎么求。考虑一下每一个点的贡献,每一个点都会对被计算$dep_i+1$次(其中$dep_i$表示$dist(i,p)$),那么很显然$\sum _{i=1}^ns_i=\sum_{i=1}^nval_i*(dep_i+1)=\sum_{i=1}^nval_i*dep_i+sum$。然后考虑一下$val_i*dep_i$,如何动态维护?->幻想乡战略游戏……

  简单来说,就是建好点分树,然后每一次及时修改和查询

  然后我们令$calc(p)$以$p$为根时的$\sum _{i=1}^nval_i*dep_i$

  然后考虑如下式子$$\sum_{i=1}^n\sum_{j=1}^nval_i*val_j*dist(i,j)$$

  是不是可以理解为在所有的点对$(i,j)$之间的所有边上加上权值$val_i*val_j$(刚好有$dist(i,j)$条边),然后再求整棵树的权值?

  然后我们考虑一下每条边的权值,肯定等于两侧的子树点权和的乘积。那么,不论是以哪一个点$p$为根,它的权值都等于$s_i*(sum-s_i)$,其中$s_i$表示这条边指向的儿子的子树的点权和

  那么,上面的式子就可以变成这样$$\sum_{i=1}^n\sum_{j=1}^nval_i*val_j*dist(i,j)=\sum_{i=1}^ns_i*(sum-s_i)$$

  又因为上式左边是不变的,所以不管选取哪一个$p$为根,右边都是不变的

  令$W=\sum_{i=1}^ns_i*(sum-s_i)$,然后可以直接$O(n)dp$出$W$,然后考虑对点的修改对$W$造成的影响

  $W=\sum_{i=1}^n\sum{j=1}^nval_i*val_j*dist(i,j)$,设点$u$的变化量为$Δv$,那么$ΔW=Δv*\sum_{j=1}^nval_j*dist(i,j)$,相当于$Δv*calc(i)$,然后可以考虑和一般的动态点分一样计算

  然后最后询问的答案就是$$W=\sum_{i=1}^ns_i*(sum-s_i)$$

  $$\sum_{i=1}^ns_i^2=\sum_{i=1}^ns_i*sum-W$$

  $$\sum_{i=1}^ns_i^2=sum(calc(i)+sum)-W$$

 // luogu-judger-enable-o2
//minamoto
#include<iostream>
#include<cstdio>
#include<algorithm>
#define ll long long
using namespace std;
#define getc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
char buf[<<],*p1=buf,*p2=buf;
template<class T>inline bool cmax(T&a,const T&b){return a<b?a=b,:;}
inline int read(){
#define num ch-'0'
char ch;bool flag=;int res;
while(!isdigit(ch=getc()))
(ch=='-')&&(flag=true);
for(res=num;isdigit(ch=getc());res=res*+num);
(flag)&&(res=-res);
#undef num
return res;
}
char sr[<<],z[];int C=-,Z;
inline void Ot(){fwrite(sr,,C+,stdout),C=-;}
inline void print(ll x){
if(C><<)Ot();if(x<)sr[++C]=,x=-x;
while(z[++Z]=x%+,x/=);
while(sr[++C]=z[Z],--Z);sr[++C]='\n';
}
const int N=;
int ver[N<<],head[N],Next[N<<];
int val[N],fa[N],pa[N],d[N],sz[N],son[N],top[N];
int n,q,tot;
void dfs1(int u,int fa){
pa[u]=fa,d[u]=d[fa]+,sz[u]=;
for(int i=head[u];i;i=Next[i]){
int v=ver[i];if(v==fa) continue;
dfs1(v,u);
sz[u]+=sz[v];if(sz[v]>sz[son[u]]) son[u]=v;
}
}
void dfs2(int u,int fa){
top[u]=fa;
if(son[u]) dfs2(son[u],fa);else return;
for(int i=head[u];i;i=Next[i])
if(ver[i]!=pa[u]&&ver[i]!=son[u])
dfs2(ver[i],ver[i]);
}
int LCA(int u,int v){
while(top[u]^top[v]){
if(d[top[u]]<d[top[v]]) swap(u,v);
u=pa[top[u]];
}
return d[u]<d[v]?u:v;
}
int dis(int u,int v){return d[u]+d[v]-(d[LCA(u,v)]<<);}
int size,rt,vis[N];
ll sum[N],sum1[N],sum2[N],sigma,omega,ans;
void getrt(int u,int fa){
sz[u]=,son[u]=;
for(int i=head[u];i;i=Next[i]){
int v=ver[i];if(v==fa||vis[v]) continue;
getrt(v,u),sz[u]+=sz[v],cmax(son[u],sz[v]);
}
cmax(son[u],size-sz[u]);
if(son[u]<son[rt]) rt=u;
}
void solve(int u,int f){
fa[u]=f,vis[u]=;int totsz=size;
for(int i=head[u];i;i=Next[i]){
int v=ver[i];
if(!vis[v]){
size=sz[v]>sz[rt]?totsz-sz[rt]:sz[v];
rt=;
getrt(v,),solve(rt,u);
}
}
}
inline void modify(int u,int v){
sum[u]+=v;
for(int i=u;fa[i];i=fa[i]){
int dist=dis(u,fa[i]);
sum[fa[i]]+=v;
sum1[fa[i]]+=dist*v;
sum2[i]+=dist*v;
}
}
inline ll calc(int u){
ll res=sum1[u];
for(int i=u;fa[i];i=fa[i]){
int dist=dis(fa[i],u);
res+=(ll)dist*(sum[fa[i]]-sum[i]);
res+=sum1[fa[i]]-sum2[i];
}
return res;
}
void DP(int u,int fa){
sz[u]=val[u];
for(int i=head[u];i;i=Next[i]){
int v=ver[i];
if(v!=fa) DP(v,u),sz[u]+=sz[v];
}
omega+=1ll*sz[u]*(sigma-sz[u]);
}
int main(){
n=read(),q=read();
for(int i=;i<n;++i){
int u=read(),v=read();
ver[++tot]=v,Next[tot]=head[u],head[u]=tot;
ver[++tot]=u,Next[tot]=head[v],head[v]=tot;
}
dfs1(,),dfs2(,);
size=n,son[rt=]=n+;
getrt(,),solve(rt,);
for(int i=;i<=n;++i)
val[i]=read(),modify(i,val[i]),sigma+=val[i];
DP(,);
while(q--){
int opt=read(),x=read();
if(opt&){
int y=read();y-=val[x];
modify(x,y),sigma+=y,omega+=y*calc(x);
val[x]+=y;
}
else print((calc(x)+sigma)*sigma-omega);
}
Ot();
return ;
}

洛谷P3676 小清新数据结构题(动态点分治+树链剖分)的更多相关文章

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

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

  2. 洛谷P3676 小清新数据结构题 【树剖 + BIT】

    题目链接 洛谷P3676 题解 我们先维护\(1\)为根的答案,再考虑换根 一开始的答案可以\(O(n)\)计算出来 考虑修改,记\(s[u]\)表示\(u\)为根的子树的权值和 当\(u\)节点产生 ...

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

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

  4. 【刷题】洛谷 P3676 小清新数据结构题

    题目背景 本题时限2s,内存限制256M 题目描述 在很久很久以前,有一棵n个点的树,每个点有一个点权. 现在有q次操作,每次操作是修改一个点的点权或指定一个点,询问以这个点为根时每棵子树点权和的平方 ...

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

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

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

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

  7. 洛谷 P3672 小清新签到题 [DP 排列]

    传送门 题意:给定自然数n.k.x,你要求出第k小的长度为n的逆序对对数为x的1~n的排列 $n \le 300, k \le 10^13$ 一下子想到hzc讲过的DP 从小到大插入,后插入不会对前插 ...

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

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

  9. [洛谷P3672]小清新签到题

    题目描述 题目还是简单一点好. 给定自然数n.k.x,你要求出第k小的长度为n的逆序对对数为x的1~n的排列a1,a2...an,然后用仙人图上在线分支定界启发式带花树上下界最小费用流解决问题,保证存 ...

随机推荐

  1. 【320】Python 2.x 与 3.x 的区别

    通过代码移植的报错进行梳理! 1. print 函数的区别 Python 2.x 中可以加空格或者括号,但是 Python 3.x 只能是括号的 # Python 2.x >>> p ...

  2. MyBatis ehcache二级缓存

    ehcache二级缓存的开启步骤: 1.导入jar 2.在映射文件中指定用的哪个缓存 3.加一个配置文件,这个配置文件在ehcache jar包中就有 使增删改对二级缓存不刷新: 对一级缓存没有用的, ...

  3. org.json库下的json的基本使用

    public class Users { private String username; private String password; public String getUsername() { ...

  4. mybatis使用foreach进行批量插入和删除操作

    一.批量插入 1.mapper层 int insertBatchRoleUser(@Param("lists") List<RoleUser> lists);//@Pa ...

  5. python在windows环境安装MySQLdb

    一.环境 系统:win7,64位 python版本:2.7.15 pip版本:10.0.1 二.安装 1. 用pip安装 pip install MySQLdb 报错: Could not find ...

  6. Qt's Undo Framework

    Overview of Qt's Undo Framework Introduction Qt's Undo Framework is an implementation of the Command ...

  7. MFC The Screen Flickers When The Image Zoomed

    问题描述 当初写MFC也是不情愿的. 既然写了,遇到一些问题. 解决也废了一切功夫.所以简单的记录一下. 这个问题,也就是使用MFC显示图像的时候, 放缩图像的过程中, 图像会一闪一闪的. 这个问题的 ...

  8. MinDos--操作系统

    MinDos--操作系统 总结 : 本次实现的是功能是为 (1)自行定义系统提示符 (2)自定义命令集(8-10个) (3)用户输入HELP以查找命令的帮助 (4)列出命令的功能,区分内部还是外部命令 ...

  9. [Training Video - 1] [Selenium Basics] [Xpath Selenium]

    FirePath Press F12, you will see :

  10. Apache ab.exe压测工具使用

    Apache的ab命令模拟多线程并发请求,测试服务器负载压力,也可以测试nginx.lighthttp.IIS等其它Web服务器的压力. 1,打开cmd,找到安装apache的目录,cd  目录进去, ...