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) \] 其中\ ...
随机推荐
- Zabbix源码安装与yum安装
一.源码安装方式:zabbix-server LAMP环境准备: #groupadd zabbix#useradd -g zabbix zabbix 1.安装依赖包: #yum install gcc ...
- 对比学习InfoNCE loss之“搬砖学习”
以下链接讲解清晰,供参考 对比学习损失(InfoNCE loss)与交叉熵损失的联系,以及温度系数的作用 - 知乎 (zhihu.com)
- P5736 质数筛
原题连接 一看到这个熟悉的输入,我们就立马反应过来要请出一维数组来记录一下输入的数据.现在数据的存储解决了,紧接着来剖析一下步骤: 输入数据 一个一个的判断是否为质数 筛去合数 输出质数 理清了思路后 ...
- scrcpy不使用adb远程控制android
1.开启服务器 CLASSPATH=/data/local/tmp/scrcpy-server.jar app_process / com.genymobile.scrcpy.Server 1.23 ...
- 查找数组中某个元素出现的次数,例如数组arr=[1,2,3,4,3,4,5,3]中target=3出现的次数
1 function(arr,target) { 2 3 let num = 0 4 5 arr.forEach((item, index) => { 6 7 if (item===target ...
- 抓包工具Fidder
第一步:直接在浏览器下载 第二步:设置Fiddler打开Fiddler, Tools-> Fiddler Options (配置完后记得要重启Fiddler)选中"Decrpt ...
- linux部署带ssl的nginx
1.前期准备 1.1:下载nginx-1.18.0版本 http://nginx.org/download/nginx-1.18.0.tar.gz 然后上传到服 务器 /usr/local ...
- nginx配置根据url的参数值进行转发
server { listen 8081; location / { set $tag ""; set $cs "/index/test/test"; prox ...
- unity task
https://blog.csdn.net/weixin_43405845/article/details/105028291
- Qt中的线程编程
在基于操作系统的程序设计中,在处理多任务时,可以有多种方法,但效率较高的当属线程方式,下面就来讨论一下在Qt中如何实现线程编程. 先来说一下什么是线程.线程(thread)是操作系统能够进行运算调度的 ...