题目大意

有一棵有\(n\)(\(n\leq 2*10^5\))个点的树,要进行\(q\)(\(q\leq 2*10^5\))次操作,每次操作是以下两种中的一种:

1.修改一个点的点权

2.指定一个点\(x\),将该点变成根,并询问此时所有点的子树点权和之平方和

题解

设\(w_i\)表示以1号点为根时,点\(i\)的子树点权和

1操作可以看成将点\(x\)到1号点的路径上的\(w\)都加上\(y\)

假设点\(x\)到\(1\)的路径上的点是\(a_1,a_2,...a_b\),那么所有\(w\)的平方和增加了\((w_{a_1}+y)^2+(w_{a_2}+y)^2+...(w_{a_b}+y)^2-(w_{a_1}^2+w_{a_2}^2+...+w{a_b}^2)\)

该式=\(w_{a_1}^2+2*w_{a_1}*y+y^2+w_{a_2}^2+2*w_{a_2}*y+y^2+...+w_{a_b}^2+2*w_{a_b}*y+y^2-(w_{a_1}^2+w_{a_2}^2+...+w{a_b}^2)\)

=\((w_{a_1}^2+w_{a_2}^2+...+w_{a_b}^2)+2*y*(w_{a_1}+w_{a_2}+...+w_{a_b})+b*y^2-(w_{a_1}^2+w_{a_2}^2+...+w{a_b}^2)\)

=\(2*y*(w_{a_1}+w_{a_2}+...+w_{a_b})+b*y^2\)

2操作已知所有\(w\)的平方和,考虑把根从1号点挪到\(x\),假设点\(x\)到\(1\)的路径上的点是\(a_1,a_2,...a_b\),其中\(a_1\)为\(x\),\(a_b\)为\(1\)

发现只有点\(x\)到\(1\)的路径上的点的子树点权和不是\(w\)

\(a_i(i\in[2,b])\)的子树点权和是\(w_{a_b}-w_{a_{i-1}}\)

\(a_1\)的子树点权和是\(w_{a_b}\)

那么 所有点的子树点权和之平方和 比 所有\(w\)的平方和 多出了 \(w_{a_b}^2+(w_{a_b}-w_{a_{1}})^2+(w_{a_b}-w_{a_{2}})^2+...+(w_{a_b}-w_{a_{b-1}})^2-(w_{a_1}^2+w_{a_2}^2+...+w_{a_b}^2)\)

该式=\(w_{a_b}^2+w_{a_b}^2-2*w_{a_b}*w_{a_1}+w_{a_{1}}^2+w_{a_b}^2-2*w_{a_b}*w_{a_2}+w_{a_{2}}^2+...+w_{a_b}^2-2*w_{a_b}*w_{a_{b-1}}+w_{a_{b-1}}^2-(w_{a_1}^2+w_{a_2}^2+...+w_{a_b}^2)\)

=\((b-1)*w_{a_b}^2-2*w_{a_b}*(w_{a_1}+...+w_{a_{b-1}})+(w_{a_1}^2+w_{a_2}^2+...+w_{a_b}^2)-(w_{a_1}^2+w_{a_2}^2+...+w_{a_b}^2)\)

=\((b-1)*w_{a_b}^2-2*w_{a_b}*(w_{a_1}+...+w_{a_{b-1}})\)

代码
#include<algorithm>
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<ctime>
#include<iomanip>
#include<iostream>
#include<map>
#include<queue>
#include<set>
#include<stack>
#include<vector>
#define rep(i,x,y) for(register int i=(x);i<=(y);++i)
#define dwn(i,x,y) for(register int i=(x);i>=(y);--i)
#define maxn 200010
#define maxm (maxn<<1)
#define LL long long
#define ls (u<<1)
#define rs (u<<1|1)
#define mi (l+r>>1)
#define view(u,k) for(int k=fir[u];k!=-1;k=nxt[k])
using namespace std;
int read()
{
int x=0,f=1;char ch=getchar();
while(!isdigit(ch)&&ch!='-')ch=getchar();
if(ch=='-')f=-1,ch=getchar();
while(isdigit(ch))x=(x<<1)+(x<<3)+ch-'0',ch=getchar();
return x*f;
}
void write(LL x)
{
if(x==0){putchar('0'),putchar('\n');return;}
int f=0;char ch[20];
if(x<0)putchar('-'),x=-x;
while(x)ch[++f]=x%10+'0',x/=10;
while(f)putchar(ch[f--]);
putchar('\n');
return;
}
int n,q,fir[maxn],nxt[maxm],vv[maxm],dfn[maxn],top[maxn],fa[maxn],tim,dep[maxn],siz[maxn],cnt;
LL key[maxn],sum[maxn],sumall,son[maxn],fakeans,mk[maxn<<2],tr[maxn<<2],to[maxn];
void ade(int u1,int v1){vv[cnt]=v1,nxt[cnt]=fir[u1],fir[u1]=cnt++;}
void getson(int u)
{
siz[u]=1,sum[u]=key[u];
view(u,k)
{
int v=vv[k];
if(v==fa[u])continue;
fa[v]=u,dep[v]=dep[u]+1,getson(v),siz[u]+=siz[v],sum[u]+=sum[v];
if(siz[v]>siz[son[u]])son[u]=v;
}fakeans+=sum[u]*sum[u];return;
}
void gettop(int u,int anc)
{
dfn[u]=++tim,top[u]=anc,to[tim]=u;
if(son[u])gettop(son[u],anc);
view(u,k){int v=vv[k];if(v!=fa[u]&&v!=son[u])gettop(v,v);}
return;
}
void pup(int u){tr[u]=tr[ls]+tr[rs];return;}
void mkad(int u,int l,int r,int k){tr[u]+=(LL)k*(LL)(r-l+1);mk[u]+=k;return;}
void pdn(int u,int l,int r){if(mk[u])mkad(ls,l,mi,mk[u]),mkad(rs,mi+1,r,mk[u]),mk[u]=0;}
void build(int u,int l,int r)
{
if(l==r){tr[u]=sum[to[l]];return;}
build(ls,l,mi),build(rs,mi+1,r),pup(u);
}
void add(int u,int l,int r,int x,int y,int k)
{
if(x<=l&&r<=y)return mkad(u,l,r,k);
pdn(u,l,r);
if(x<=mi)add(ls,l,mi,x,y,k);
if(y>mi)add(rs,mi+1,r,x,y,k);
return pup(u);
}
LL ask(int u,int l,int r,int x,int y)
{
if(x<=l&&r<=y)return tr[u];
pdn(u,l,r);
LL res=0;
if(x<=mi)res+=ask(ls,l,mi,x,y);
if(y>mi)res+=ask(rs,mi+1,r,x,y);
return res;
}
LL askrd(int u)
{
LL res=0;
while(top[u]!=1)res+=ask(1,1,n,dfn[top[u]],dfn[u]),u=fa[top[u]];
res+=ask(1,1,n,1,dfn[u]);
return res;
}
LL askrd2(int u)
{
LL res=0;
while(top[u]!=1)res+=ask(1,1,n,dfn[top[u]],dfn[u]),u=fa[top[u]];
if(u!=1)res+=ask(1,1,n,2,dfn[u]);
return res;
}
void addrd(int u,int k)
{
while(top[u]!=1)add(1,1,n,dfn[top[u]],dfn[u],k),u=fa[top[u]];
add(1,1,n,1,dfn[u],k);return;
}
int main()
{
n=read(),q=read();
memset(fir,-1,sizeof(fir));
rep(i,1,n-1){int x=read(),y=read();ade(x,y),ade(y,x);}
rep(i,1,n)key[i]=sum[i]=read();
getson(1),gettop(1,1),build(1,1,n);
while(q--)
{
int f=read();
if(f==1){int x=read();LL y=read();y-=key[x],key[x]+=y,fakeans+=2ll*y*askrd(x)+y*y*(dep[x]+1),addrd(x,y);}
else{int x=read();LL tmp=ask(1,1,n,1,1);write(fakeans+dep[x]*tmp*tmp-2ll*tmp*askrd2(x));}
}
return 0;
}

并不对劲的p3676:小清新数据结构题的更多相关文章

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

  9. [Luogu3676]小清新数据结构题

    题面戳我 题意:给一棵树,树上有点权,每次操作为修改一个点的点权,或者是询问以某个点为根时,每棵子树(以每个点为根,就有n棵子树)点权和的平方和. \(n\le2*10^5\),保证答案在long l ...

随机推荐

  1. PTA 04-树5 Root of AVL Tree (25分)

    题目地址 https://pta.patest.cn/pta/test/16/exam/4/question/668 5-6 Root of AVL Tree   (25分) An AVL tree ...

  2. 事件和委托: 第 6 页 .Net Framework中的委托与事件

    原文发布时间为:2008-11-01 -- 来源于本人的百度文章 [由搬家工具导入] .Net Framework中的委托与事件 尽管上面的范例很好地完成了我们想要完成的工作,但是我们不仅疑惑:为什么 ...

  3. poj3532求生成树中最大权与最小权只差最小的生成树+hoj1598俩个点之间的最大权与最小权只差最小的路经。

    该题是最小生成树问题变通活用,表示自己开始没有想到该算法:先将所有边按权重排序,然后枚举最小边,求最小生成树(一个简单图的最小生成树的最大权是所有生成树中最大权最小的,这个容易理解,所以每次取最小边, ...

  4. (二)Commonjs规范与模块化

    在之前的学习中我们使用require()来引入我们需要的包,这其实就是模块化,各模块相互独立,可以通过某种方式引入别的模块.而这些引入方式都是遵循一定的规范的,这就是CommonJS规范. 一.Com ...

  5. SOJ 4467 easyproblem 2【欧拉函数 最大公因数和】

    这题wa的莫名其妙,郁闷了一下午,队友暴力一发跟我答案也是一样.后来队友说试试把%I64d换成%lld,果然一下ac...(暴露了在soj做题少.. ac之后排在ranklist的最后一名...目前也 ...

  6. Codeforces 659D Bicycle Race【计算几何】

    题目链接: http://codeforces.com/contest/659/problem/D 题意: 若干条直线围城的湖,给定直线的端点,判断多少个转点会有危险?(危险是指直走的的话会掉进水里) ...

  7. css三大特性

    层叠性: 当多个样式(样式的优先级相同)作用于同一个(同一类)标签时,样式发生了冲突,总是执行后边的代码(后边代码层叠前边的代码).和标签调用选择器的顺序没有关系. 继承性: 文字的大多属性都可以继承 ...

  8. 一个基于JBoss5.1+EJB3.0 登陆应用

    花了几天的时间研究了一下EJB的使用,一直以来都主要是在写终端中的程序,对Java框架的相关的开发非常不熟悉,中间遇到了不少麻烦,还好总算都攻克了.写篇日志记录一下. 经验总结 为什么选择JBoss5 ...

  9. 重载和重写在jvm运行中的区别(一)

    1.重载(overload)方法 对重载方法的调用主要看静态类型,静态类型是什么类型,就调用什么类型的参数方法. 2.重写(override)方法 对重写方法的调用主要看实际类型.实际类型如果实现了该 ...

  10. Android手机中UID、PID作用及区别

    PID 指进程ID. PID是进程的身份标识,程序一旦运行,就会给应用分配一个独一无二的PID(ps:一个应用可能包含多个进程,每个进程有唯一的一个PID) 进程终止后PID会被系统收回,再次打开应用 ...