luogu 3676小清新数据结构题
真·小清新...
其实本题正解是动态点分治,但是考虑到那个东西需要先大力推导一波再套上一个幻想乡战略游戏的搞法,所以还不如大力推导一波,然后无脑套上一个树剖+线段树写法...
首先我们考虑没有换根操作:
没有换根操作时,设每次修改的变化量为$\delta$,很显然每次修改时只会影响一条树链上的贡献,设$s_{i}$表示以$i$为根节点的子树权值和,那么每次修改对答案产生的贡献是:
$\sum_{i\in [p~root]}(s_{i}+\delta)^{2}-\sum_{i\in [p~root]}s_{i}^{2}$
展开这个表达式,得:
$dep_{p}\delta^{2}+2\delta\sum_{i\in [p~root]}s_{i}$
也就是说,我们实际维护的是$s_{i}$,每次修改只需给答案加上那个表达式即可
而维护$s_{i}$可以简单地树剖+线段树区间修改,区间查询算得
那么考虑下一个问题:
如果换根怎么办?
我们考虑换根之后对答案的影响:
显然要点仍然在从这个节点到根的路径上:
我们设路径上的每个点为$p_{1},p_{2},...p_{dep}$(按顺序)
设对于点$p_{i}$,在以$1$为根时子树点权和为$s_{i}$,在以$p$为根时点权和为$s^{'}_{i}$
那么我们考虑:对任意一个$i$,都满足:$s_{i}+s^{'}_{i+1}=s_{1}=s^{'}_{dep}$
也就是整棵树的点权和等于一个节点上半部分点权和+下半部分点权和
于是我们来推导一下现在的答案:
设以$1$为根的答案为$ans_{1}$
那么$ans=ans_{1}-\sum_{i=1}^{dep}s_{i}^{2}+\sum_{i=1}^{dep}(s^{'}_{i})^{2}$
借助上面的表达式,得到:
$ans=ans_{1}-\sum_{i=1}{dep}s_{i}^{2}+\sum_{i=1}^{dep-1}(s_{1}-s_{i+1})^{2}+(s^{'}_{dep})^{2}$
那么也就是:
$ans=ans_{1}-\sum_{i=1}^{dep}s_{i}^{2}+deps_{1}^{2}-2s_{1}\sum_{i=2}^{dep}s_{i}+\sum_{i=2}^{dep}s_{i}^{2}$
于是:
$ans=ans_{1}+(dep-1)s_{1}^{2}-2s_{1}\sum_{i=1}^{dep}s_{i}+2s_{1}$
整理一下:
$ans=ans_{1}+s_{1}[(dep+1)s_{1}-2\sum_{i=1}^{dep}s_{i}]$
因此我们仍然只需维护$s_{i}$即可
这样树剖+线段树就可以完美解决这个问题了
贴代码:
// luogu-judger-enable-o2
#include <cstdio>
#include <cmath>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#include <queue>
#include <stack>
#define rt1 rt<<1
#define rt2 (rt<<1)|1
#define ll long long
using namespace std;
struct Edge
{
int nxt,to;
}edge[400005];
struct Seg_tree
{
ll lazy,sum;
}tree[800005];
int head[200005];
int cnt=1;
int siz[200005],son[200005],nnum[200005],onum[200005],ttop[200005],dep[200005],f[200005];
ll w[200005],s[200005];
int tot;
ll ans=0;
int n,m;
void add(int l,int r)
{
edge[cnt].nxt=head[l];
edge[cnt].to=r;
head[l]=cnt++;
}
void dfs(int x,int fx)
{
siz[x]=1,f[x]=fx,dep[x]=dep[fx]+1,s[x]=w[x];
for(int i=head[x];i;i=edge[i].nxt)
{
int to=edge[i].to;
if(to==fx)continue;
dfs(to,x);
siz[x]+=siz[to],s[x]+=s[to],son[x]=siz[son[x]]<siz[to]?to:son[x];
}
ans+=s[x]*s[x];
}
void redfs(int x,int topx,int fx)
{
ttop[x]=topx,nnum[x]=++tot,onum[tot]=x;
if(son[x])redfs(son[x],topx,x);
for(int i=head[x];i;i=edge[i].nxt)
{
int to=edge[i].to;
if(to==fx||to==son[x])continue;
redfs(to,to,x);
}
}
void buildtree(int rt,int l,int r)
{
if(l==r){tree[rt].sum=s[onum[l]];return;}
int mid=(l+r)>>1;
buildtree(rt1,l,mid),buildtree(rt2,mid+1,r);
tree[rt].sum=tree[rt1].sum+tree[rt2].sum;
}
void pushdown(int rt,int l,int r)
{
tree[rt1].lazy+=tree[rt].lazy,tree[rt2].lazy+=tree[rt].lazy;
int mid=(l+r)>>1;
tree[rt1].sum+=(mid-l+1)*tree[rt].lazy,tree[rt2].sum+=(r-mid)*tree[rt].lazy;
tree[rt].lazy=0;
}
void update(int rt,int l,int r,int lq,int rq,ll v)
{
if(l>=lq&&r<=rq)
{
tree[rt].lazy+=v,tree[rt].sum+=(r-l+1)*v;
return;
}
if(tree[rt].lazy)pushdown(rt,l,r);
int mid=(l+r)>>1;
if(lq<=mid)update(rt1,l,mid,lq,rq,v);
if(rq>mid)update(rt2,mid+1,r,lq,rq,v);
tree[rt].sum=tree[rt1].sum+tree[rt2].sum;
}
ll query(int rt,int l,int r,int lq,int rq)
{
if(l>=lq&&r<=rq)return tree[rt].sum;
int mid=(l+r)>>1;
if(tree[rt].lazy)pushdown(rt,l,r);
ll ret=0;
if(lq<=mid)ret+=query(rt1,l,mid,lq,rq);
if(rq>mid)ret+=query(rt2,mid+1,r,lq,rq);
return ret;
}
void pushup(int x,ll v)
{
while(x){update(1,1,n,nnum[ttop[x]],nnum[x],v),x=f[ttop[x]];}
}
ll l_query(int x)
{
ll ret=0;
while(x){ret+=query(1,1,n,nnum[ttop[x]],nnum[x]),x=f[ttop[x]];}
return ret;
}
template <typename T>inline void read(T &x)
{
T f=1,c=0;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){c=c*10+ch-'0';ch=getchar();}
x=c*f;
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<n;i++)
{
int x,y;
read(x),read(y);
add(x,y),add(y,x);
}
for(int i=1;i<=n;i++)read(w[i]);
dfs(1,0),redfs(1,1,1);
buildtree(1,1,n);
while(m--)
{
int typ;
read(typ);
if(typ==1)
{
int x;
ll v;
read(x),read(v);
ans+=(v-w[x])*(v-w[x])*dep[x];
ans+=2*(v-w[x])*l_query(x);
pushup(x,v-w[x]);
w[x]=v;
}else
{
int x;
read(x);
ll temp1=query(1,1,n,nnum[1],nnum[1]);
ll temp2=l_query(x);
ll temps=temp1*((dep[x]+1)*temp1-2*temp2);
printf("%lld\n",ans+temps);
}
}
return 0;
}
luogu 3676小清新数据结构题的更多相关文章
- Luogu 3676 小清新数据结构题
推荐博客: http://www.cnblogs.com/Mychael/p/9257242.html 感觉还挺好玩的 首先考虑以1为根,把每一个点子树的权值和都算出来,记为$val_{i}$,那么在 ...
- 【Luogu3676】小清新数据结构题(动态点分治)
[Luogu3676]小清新数据结构题(动态点分治) 题面 洛谷 题解 先扯远点,这题我第一次看的时候觉得是一个树链剖分+线段树维护. 做法大概是这样: 我们先以任意一个点为根,把当前点看成是一棵有根 ...
- 洛谷 P3676 小清新数据结构题
https://www.luogu.org/problemnew/show/P3676 这题被我当成动态dp去做了,码了4k,搞了一个换根的动态dp #include<cstdio> #i ...
- [Luogu3676]小清新数据结构题
题面戳我 题意:给一棵树,树上有点权,每次操作为修改一个点的点权,或者是询问以某个点为根时,每棵子树(以每个点为根,就有n棵子树)点权和的平方和. \(n\le2*10^5\),保证答案在long l ...
- [P3676]小清新数据结构题
Description: 给你一棵树,每次询问以一个点为根时所有子树点权和的平方和 带修改 Hint: \(n\le 2*10^5\) Solution: 这题只要推出式子就很简单了 如果不换根这个平 ...
- Luogu3676 小清新数据结构题 动态点分治
传送门 换根类型的统计问题动态点分治都是很好做的. 设所有点的点权和为$sum$ 首先,我们先不考虑求$\sum\limits_i s_i^2$,先考虑如何在换根的情况下求$\sum\limits_i ...
- 洛谷P3676 小清新数据结构题(动态点分治+树链剖分)
传送门 感觉这题做下来心态有点崩……$RMQ$求$LCA$没有树剖快我可以理解为是常数太大……然而我明明用了自以为不会退化的点分然而为什么比会退化的点分跑得反而更慢啊啊啊啊~~~ 先膜一波zsy大佬 ...
- [luogu3676] 小清新数据结构题 [树链剖分+线段树]
题面 传送门 思路 本来以为这道题可以LCT维护子树信息直接做的,后来发现这样会因为splay形态改变影响子树权值平方和,是splay本身的局限性导致的 所以只能另辟蹊径 首先,我们考虑询问点都在1的 ...
- 洛谷 P3676 - 小清新数据结构题(动态点分治)
洛谷题面传送门 题目名称好评(实在是太清新了呢) 首先考虑探究这个"换根操作"有什么性质.我们考虑在换根前后虽然每个点的子树会变,但整棵树的形态不会边,换句话说,割掉每条边后,得到 ...
- 洛谷P3676 小清新数据结构题 [动态点分治]
传送门 思路 这思路好妙啊! 首先很多人都会想到推式子之后树链剖分+线段树,但这样不够优美,不喜欢. 脑洞大开想到这样一个式子: \[ \sum_{x} sum_x(All-sum_x) \] 其中\ ...
随机推荐
- 【jquery easyUI 拓展
jquery-easyui本身没有提供列锁定/解锁的接口,并且其原有的列隐藏/显示在符合表头的情况下会出现错位,我在项目中遇到了这两个问题,在参考了网上许多解决方案后,编写了一个拓展插件,基本上解决了 ...
- 通过一个简单的实例来展示 Java 编程,创建文件 HelloWorld.java
public class HelloWorld { public static void main(String[] args) { System.out.println("Hello Wo ...
- c/c++工程中为什么仅仅main.cpp引用其他源文件的头文件不够,源文件还要引用自身的头文件?
原博客链接: https://blog.csdn.net/khwkhwkhw/article/details/49798985?utm_source=app&from=timeline 引言: ...
- EBS的配置文件
默认账套 select fnd_profile.value('GL_SET_OF_BKS_ID') FROM DUAL; >> 2026 这样就能通过2026去获取一些账套上的配置 比如c ...
- Appkiz.Base、Appkiz.Base.Languages
环境: ILSpy version 4.0.0.4319-beta2 选择 C#6.0 Visual Studio 2015 直接保存代码,直接用Visual Studio 2015打开.csprj文 ...
- onnxruntime源码解析之C接口简介
一.C接口 1. 简介 其他语言的接口都是在C接口的基础上,进一步的封装. C的接口头文件为:onnxruntime_c_api.h 头文件内包含了详细的注释和说明. 总体上,除了一些数据结构的定义, ...
- AndroidStudio 集成kotlin,以及Kotlin-gradle-plugin-1.5.0.jar 下载失败
配置Kotlin buildscript { ext.kotlin_version = '1.5.0' repositories { maven{url 'http://maven.aliyun.co ...
- serializers序列化函数简单入门
1. 创建Django项目和应用程序 首先,我们需要创建一个Django项目和一个Django应用程序.如果你已经有了Django项目和应用程序,请跳过这一步. $ django-admin star ...
- LOOP GROUP BY 分组循环的使用方法小栗子
原文链接:https://blog.csdn.net/lmf496891416/article/details/111317377 1.格式: LOOP AT 内表 INTO DATA(工作区) GR ...
- mybatis 一级、二级缓存机制
MyBatis 提供了对缓存的支持,分为一级缓存和二级缓存 一级缓存是 SqlSession 级别的缓存.在操作数据库时需要构造 SqlSession 对象,在对象中有一个数据结构(HashMap)用 ...