博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
洛谷P3676 小清新数据结构题(动态点分治+树链剖分)
阅读量:5892 次
发布时间:2019-06-19

本文共 3111 字,大约阅读时间需要 10 分钟。

 

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

  先膜一波

  讲讲做法。题目的要求是给定一个根$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$$

1 // luogu-judger-enable-o2  2 //minamoto  3 #include
4 #include
5 #include
6 #define ll long long 7 using namespace std; 8 #define getc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++) 9 char buf[1<<21],*p1=buf,*p2=buf; 10 template
inline bool cmax(T&a,const T&b){
return a
1<<20)Ot();if(x<0)sr[++C]=45,x=-x; 25 while(z[++Z]=x%10+48,x/=10); 26 while(sr[++C]=z[Z],--Z);sr[++C]='\n'; 27 } 28 const int N=200005; 29 int ver[N<<1],head[N],Next[N<<1]; 30 int val[N],fa[N],pa[N],d[N],sz[N],son[N],top[N]; 31 int n,q,tot; 32 void dfs1(int u,int fa){ 33 pa[u]=fa,d[u]=d[fa]+1,sz[u]=1; 34 for(int i=head[u];i;i=Next[i]){ 35 int v=ver[i];if(v==fa) continue; 36 dfs1(v,u); 37 sz[u]+=sz[v];if(sz[v]>sz[son[u]]) son[u]=v; 38 } 39 } 40 void dfs2(int u,int fa){ 41 top[u]=fa; 42 if(son[u]) dfs2(son[u],fa);else return; 43 for(int i=head[u];i;i=Next[i]) 44 if(ver[i]!=pa[u]&&ver[i]!=son[u]) 45 dfs2(ver[i],ver[i]); 46 } 47 int LCA(int u,int v){ 48 while(top[u]^top[v]){ 49 if(d[top[u]]
sz[rt]?totsz-sz[rt]:sz[v]; 72 rt=0; 73 getrt(v,0),solve(rt,u); 74 } 75 } 76 } 77 inline void modify(int u,int v){ 78 sum[u]+=v; 79 for(int i=u;fa[i];i=fa[i]){ 80 int dist=dis(u,fa[i]); 81 sum[fa[i]]+=v; 82 sum1[fa[i]]+=dist*v; 83 sum2[i]+=dist*v; 84 } 85 } 86 inline ll calc(int u){ 87 ll res=sum1[u]; 88 for(int i=u;fa[i];i=fa[i]){ 89 int dist=dis(fa[i],u); 90 res+=(ll)dist*(sum[fa[i]]-sum[i]); 91 res+=sum1[fa[i]]-sum2[i]; 92 } 93 return res; 94 } 95 void DP(int u,int fa){ 96 sz[u]=val[u]; 97 for(int i=head[u];i;i=Next[i]){ 98 int v=ver[i]; 99 if(v!=fa) DP(v,u),sz[u]+=sz[v];100 }101 omega+=1ll*sz[u]*(sigma-sz[u]);102 }103 int main(){104 n=read(),q=read();105 for(int i=1;i

 

转载于:https://www.cnblogs.com/bztMinamoto/p/9486869.html

你可能感兴趣的文章
博客园博客自动生成三级目录(generate three levels content using JS in cnblogs)
查看>>
关于多线程的那些事
查看>>
js 将json字符串转换为json对象的方法解析
查看>>
1. Two Sum
查看>>
让浏览器不再显示 https 页面中的 http 请求警报
查看>>
hdu4893Wow! Such Sequence! (线段树)
查看>>
Android 最简单的SD卡文件遍历程序
查看>>
JavaScript获取DOM元素位置和尺寸大小
查看>>
1065: 贝贝的加密工作
查看>>
lintcode 单词接龙II
查看>>
WEB版一次选择多个文件进行批量上传(WebUploader)的解决方案
查看>>
Redis之 命令行 操作
查看>>
Jvm(46),指令集----对象创建与访问指令
查看>>
EL 表达式小结
查看>>
内部排序
查看>>
jQuery EasyUI API 中文文档 - 组合(Combo)
查看>>
10个关于 Dropbox 的另类功用(知乎问答精编)[还是转来了]
查看>>
Oracle体系结构
查看>>
用Modelsim仿真QII FFT IP核的时候出现的Error: Illegal target for defparam
查看>>
javascript Error对象详解
查看>>