传送门

  感觉这题做下来心态有点崩……$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. 自定义annotation-----转载

    Java从JDK5.0开始便提供了四个meta-annotation用于自定义注解的时候使用,这四个注解为:@Target,@Retention,@Documented 和@Inherited. @T ...

  2. cas增加验证码

    参考地址:https://blog.csdn.net/attackmind/article/details/52052502 参考地址:https://blog.csdn.net/jadyer/art ...

  3. Excel VBA入门(九)操作工作薄

    虽然我前面讲过,在VBA中操作工作薄并不是件明智的事,但有些时候,还是避免不了要这么做.绝大多数情况下,我们要做的是获取到某个工作薄对象,并以此来获得其中的工作表对象,然后再对工作表中的数据进行处理. ...

  4. jmeter 常用函数

    ${__Random(10000000,19999999,str)};vars.put("msisdn","182"+${__evalVar(str)});

  5. 将Oracle数据库设置为归档模式及非归档模式

    一.将Oracle数据库设置为归档模式 1)sql>shutdown normal/immediate;2)sql>startup mount;3)sql>alter databas ...

  6. 转载:Candy? 在线性时间内求出素数与欧拉函数

    转载自:http://www.cnblogs.com/candy99/p/6200660.html 2818: Gcd Time Limit: 10 Sec  Memory Limit: 256 MB ...

  7. 这样的UX设计师简历,HR分分钟给你来电话

    BLS调查显示,软件开发和IT,用户体验设计,产品经理和项目管理这三个职位在未来有非凡的发展前景.其中,用户体验设计师是目前最有需求的创意产业工作之一.10年里就业增长率高达22.1%,工作岗位数3, ...

  8. 关闭Found duplicated code

    IDEA中的这个“发现重复代码 - Found duplicated code“的这个提示甚是烦躁. Settings —> Editor —> Inspections —> Gen ...

  9. 15 Independent Alleles

    Problem Figure 2. The probability of each outcome for the sum of the values on two rolled dice (blac ...

  10. java 文件中 定义一个字符串,它的默认编码是什么?

    .java 文件的编码就是 String 字符串的编码 File 文件的编码就是 文件内容的编码 request 的设置的编码就是inputstream 的编码 jvm 的默认编码(the defau ...