[P3676]小清新数据结构题
Description:
给你一棵树,每次询问以一个点为根时所有子树点权和的平方和
带修改
Hint:
\(n\le 2*10^5\)
Solution:
这题只要推出式子就很简单了
如果不换根这个平方和树剖直接做就行了
考虑换根的影响了哪些点的贡献
显然只影响了\(1\)到\(u\)的路径上的点
把1到\(u\)这条路径上的点依次标记为\(1,2,3......k\)
我们设\(a_i\)为以1为根时\(i\)的点权和,\(b_i\)为以\(u\)为根的点权和
\(Ans=ans_1-\sum a_i^2 + \sum b_i^2\)
注意到\(a_{i+1}+b_i=sum\)
\(Ans=ans_1-\sum a_i^2 -a_1^2+b_k^2 + \sum (sum-a_{i+1})^2\)
消掉\(\sum a_i^2\)
\(Ans=ans_1-k*sum^2-2*sum*\sum a_i\)
预处理出\(ans1\),每次算一条链就行
(注意最后并没有算\(a_1\))
#include <map>
#include <set>
#include <stack>
#include <cmath>
#include <queue>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#define ls p<<1
#define rs p<<1|1
using namespace std;
typedef long long ll;
const ll mxn=1e6+5;
ll n,m,cnt,hd[mxn];
inline ll read() {
char c=getchar(); ll x=0,f=1;
while(c>'9'||c<'0') {if(c=='-') f=-1;c=getchar();}
while(c<='9'&&c>='0') {x=(x<<3)+(x<<1)+(c&15);c=getchar();}
return x*f;
}
inline void chkmax(ll &x,ll y) {if(x<y) x=y;}
inline void chkmin(ll &x,ll y) {if(x>y) x=y;}
struct ed {
ll to,nxt;
}t[mxn<<1];
ll df;
ll a[mxn],f[mxn],sz[mxn],rk[mxn],dfn[mxn],top[mxn],son[mxn];
ll tr[mxn<<2],pw[mxn<<2],tag[mxn<<2],len[mxn<<2],sum[mxn];
inline void add(ll u,ll v) {
t[++cnt]=(ed) {v,hd[u]}; hd[u]=cnt;
}
void dfs1(ll u,ll fa) {
f[u]=fa; sz[u]=1; sum[u]=a[u];
for(ll i=hd[u];i;i=t[i].nxt) {
ll v=t[i].to;
if(v==fa) continue ;
dfs1(v,u); sz[u]+=sz[v]; sum[u]+=sum[v];
if(sz[son[u]]<sz[v]) son[u]=v;
}
}
void dfs2(ll u,ll tp) {
dfn[u]=++df; rk[df]=u; top[u]=tp;
if(son[u]) dfs2(son[u],tp);
for(ll i=hd[u];i;i=t[i].nxt) {
ll v=t[i].to;
if(v==f[u]||v==son[u]) continue ;
dfs2(v,v);
}
}
void push_up(ll p) {
tr[p]=tr[ls]+tr[rs];
pw[p]=pw[ls]+pw[rs];
}
void push_down(ll p) {
if(tag[p]) {
tag[ls]+=tag[p]; tag[rs]+=tag[p];
pw[ls]+=2*tr[ls]*tag[p]+tag[p]*tag[p]*len[ls];
pw[rs]+=2*tr[rs]*tag[p]+tag[p]*tag[p]*len[rs];
tr[ls]+=len[ls]*tag[p];
tr[rs]+=len[rs]*tag[p];
tag[p]=0;
}
}
void build(ll l,ll r,ll p) {
if(l==r) {
len[p]=1;
tr[p]=sum[rk[l]];
pw[p]=sum[rk[l]]*sum[rk[l]];
return ;
}
ll mid=(l+r)>>1;
build(l,mid,ls); build(mid+1,r,rs);
push_up(p); len[p]=r-l+1;
}
void update(ll l,ll r,ll ql,ll qr,ll val,ll p) {
if(ql<=l&&r<=qr) {
tag[p]+=val;
pw[p]+=val*val*len[p]+2*val*tr[p];
tr[p]+=val*len[p];
return ;
}
ll mid=(l+r)>>1; push_down(p);
if(ql<=mid) update(l,mid,ql,qr,val,ls);
if(qr>mid) update(mid+1,r,ql,qr,val,rs);
push_up(p);
}
ll query(ll l,ll r,ll ql,ll qr,ll p) {
if(ql<=l&&r<=qr) return tr[p];
ll mid=(l+r)>>1; push_down(p); ll res=0;
if(ql<=mid) res+=query(l,mid,ql,qr,ls);
if(qr>mid) res+=query(mid+1,r,ql,qr,rs);
return res;
}
ll tp;
void modify(ll x,ll y) {
y-=a[x]; a[x]+=y; tp+=y;
while(x) {
update(1,n,dfn[top[x]],dfn[x],y,1);
x=f[top[x]];
}
}
ll ask(ll x) {
ll ans=pw[1],res1=0,res2=0;
while(top[x]!=1) {
res1+=dfn[x]-dfn[top[x]]+1;
res2+=query(1,n,dfn[top[x]],dfn[x],1);
x=f[top[x]];
}
res1+=dfn[x]-1;
if(x!=1) res2+=query(1,n,dfn[1]+1,dfn[x],1);
return ans+tp*(res1*tp-res2*2);
}
int main()
{
n=read(); m=read(); ll u,v,opt,x,y;
for(ll i=1;i<n;++i) {
u=read(); v=read();
add(u,v); add(v,u);
}
for(ll i=1;i<=n;++i) a[i]=read();
dfs1(1,0); dfs2(1,1); build(1,n,1); tp=sum[1];
for(ll i=1;i<=m;++i) {
opt=read();
if(opt==1) {
x=read(); y=read();
modify(x,y);
}
else x=read(),printf("%lld\n",ask(x));
}
return 0;
}
[P3676]小清新数据结构题的更多相关文章
- 洛谷 P3676 小清新数据结构题
https://www.luogu.org/problemnew/show/P3676 这题被我当成动态dp去做了,码了4k,搞了一个换根的动态dp #include<cstdio> #i ...
- 洛谷P3676 小清新数据结构题 【树剖 + BIT】
题目链接 洛谷P3676 题解 我们先维护\(1\)为根的答案,再考虑换根 一开始的答案可以\(O(n)\)计算出来 考虑修改,记\(s[u]\)表示\(u\)为根的子树的权值和 当\(u\)节点产生 ...
- 洛谷P3676 小清新数据结构题(动态点分治+树链剖分)
传送门 感觉这题做下来心态有点崩……$RMQ$求$LCA$没有树剖快我可以理解为是常数太大……然而我明明用了自以为不会退化的点分然而为什么比会退化的点分跑得反而更慢啊啊啊啊~~~ 先膜一波zsy大佬 ...
- 洛谷 P3676 - 小清新数据结构题(动态点分治)
洛谷题面传送门 题目名称好评(实在是太清新了呢) 首先考虑探究这个"换根操作"有什么性质.我们考虑在换根前后虽然每个点的子树会变,但整棵树的形态不会边,换句话说,割掉每条边后,得到 ...
- 洛谷P3676 小清新数据结构题 [动态点分治]
传送门 思路 这思路好妙啊! 首先很多人都会想到推式子之后树链剖分+线段树,但这样不够优美,不喜欢. 脑洞大开想到这样一个式子: \[ \sum_{x} sum_x(All-sum_x) \] 其中\ ...
- 【刷题】洛谷 P3676 小清新数据结构题
题目背景 本题时限2s,内存限制256M 题目描述 在很久很久以前,有一棵n个点的树,每个点有一个点权. 现在有q次操作,每次操作是修改一个点的点权或指定一个点,询问以这个点为根时每棵子树点权和的平方 ...
- 并不对劲的p3676:小清新数据结构题
题目大意 有一棵有\(n\)(\(n\leq 2*10^5\))个点的树,要进行\(q\)(\(q\leq 2*10^5\))次操作,每次操作是以下两种中的一种: 1.修改一个点的点权 2.指定一个点 ...
- 【Luogu3676】小清新数据结构题(动态点分治)
[Luogu3676]小清新数据结构题(动态点分治) 题面 洛谷 题解 先扯远点,这题我第一次看的时候觉得是一个树链剖分+线段树维护. 做法大概是这样: 我们先以任意一个点为根,把当前点看成是一棵有根 ...
- [Luogu3676]小清新数据结构题
题面戳我 题意:给一棵树,树上有点权,每次操作为修改一个点的点权,或者是询问以某个点为根时,每棵子树(以每个点为根,就有n棵子树)点权和的平方和. \(n\le2*10^5\),保证答案在long l ...
随机推荐
- JS学习笔记Day9
一.BOM (一)概念:是 Browser object model 的缩写,简称浏览器对象模型. BOM 提供了独立于内容而与浏览器窗口进行交互的对象 由于 BOM 主要用于管理窗口与窗口之间的通讯 ...
- 2018年秋季学期《c语言程序设计》助教总结
<c语言程序设计>第七周助教总结 <c语言程序设计>第八周助教总结 <c语言程序设计>第九周助教总结 <c语言程序设计>第十周助教总结 <c语言程 ...
- pandas常用函数之diff
diff函数是用来将数据进行某种移动之后与原数据进行比较得出的差异数据,举个例子,现在有一个DataFrame类型的数据df,如下: index value1 A 0 B 1 C 2 D 3 如果执行 ...
- Numpy 系列(九)- 结构化数组
简介 之前我们操作Numpy的数组时,都是通过索引来操作的.针对二维数组,使用索引可以完成对行.列的操作.但是这是非常不直观的.可以把二维数组想象成一个excel表格,如果表格没有列名,操作起来会 ...
- 分布式监控系统开发【day37】:表结构设计(二)
一.表结构关系图 二.表结构需求讨论 1.主机表(Host) 1.解决了什么问题? 1.如果我不想让它监控了,就有一个开关的东西给它禁掉2.主机存活状态检测间隔 2.代码 class Host(mod ...
- command not found
1.问题(problem) #wget gzip.x86_64 0:1.5-10.el7 -bash: wget command not found 2.解决(solution) 两个都能用 yum ...
- 第一节:从面向对象思想(oo)开发、接口、抽象类以及二者比较
一. 面向对象思想 1. 面向过程(OP)和面向对象(OO)的区别: (1):面向过程就是排着用最简单的代码一步一步写下去,没有封装,当业务复杂的时候,改动就很麻烦了 (2):面向对象将复杂的业务分离 ...
- UML建工工具
本篇博文简单介绍一下自己在搜索UML建模工具的过程中收集到的一些信息. 如果想用中文的,可以考虑楚凡科技的Trufun Plato,不过最近好像没有怎么更新了. 很多前辈以前用的是Rational R ...
- mysql MHA架构搭建过程
[环境介绍] 系统环境:Red Hat Enterprise Linux 7 + 5.7.18 + MHA version 0.57 系统 IP 主机名 备注 版本 xx系统 192.168.142. ...
- java核心36
1 Java平台 Java采用的是解释和编译混合的模式.它首先通过javac将源码编译成字节码文件class.然后在运行的时候通过解释器或者JIT将字节码转换成最终的机器码.只是用解释器的缺点:抛弃了 ...