推荐博客: http://www.cnblogs.com/Mychael/p/9257242.html

感觉还挺好玩的

首先考虑以1为根,把每一个点子树的权值和都算出来,记为$val_{i}$,那么在所有操作都没有开始的时候(以$1$为根的)$ans_{1} = \sum_{i= 1}^{n}val_{i}^{2}$

考虑到一个修改的操作只会对修改的点$x$到根($1$)链上的点产生影响,那么一次修改只要修对这条树链上的点增加$v - a_{x}$(假设修改后的值为$v$)就好了。

链剖之后线段树维护一下$val_{i}$,区间修改就很简单。

然后考虑换根:

我们发现当以$x$为根的时候,$x$原来的子树显然不会受到影响,而变化了的是原来的根$1$到$x$的链上的点,不妨设有$k$个结点,换根前(以$1$为根)的每个结点子树$val$值和为$a_{i}$,换根后(以$x$为根)的每个结点子树$val$值和为$b_{i}$

有一条显然的性质:$a_{i + 1} + b_{i} = a_{1} = b_{k}$都等于原来全部结点的$val$值和

那么换根之后的答案  $ans_{x} = ans_{1} - \sum_{i = 1}^{k}a_{i}^{2} + \sum_{i = 1}^{k}b_{i}^{2}$

代入上面的那条性质消掉$b$,发现$ans_{x} = ans_{1} + (k - 1)a_{1}^{2} - 2a_{1}\sum_{i = 2}^{k}a_{i}$

设$s_{i}$表示$i$的子树中所有$val$值和,那么$ans_{x} = ans_{1} + s_{1}((k + 1) s_{1} - 2\sum_{i = 1}^{k}s_{i})$。

容易发现这个$k$即为$dep_{x}$,而这个$\sum_{i = 1}^{k}s_{i}$ 和 $s_{1}$显然可以用线段树维护出来

考虑一下, 一次修改还会对$ans_{1}$产生影响,$ans_{1} += \sum_{i = 1}^{tot}(val_{i}+ \Delta v)^{2} - \sum_{i = 1}^{tot}val_{i}^{2} = tot\Delta v^{2} + 2\Delta v\sum_{i = 1}^{tot}val_{i}$。

因为每次发生变化的只有一条树链上的点,所以$tot = dep_{x}$,这个原来的$\sum_{i = 1}^{tot}val_{i}$可以在跳轻重链的过程中算出来。

时间复杂度$O(nlog^{2}n)$。

Code:

#include <cstdio>
#include <cstring>
using namespace std;
typedef long long ll; const int N = 2e5 + ; int n, qn, dfsc = , dep[N], siz[N], id[N];
int tot = , head[N], top[N], fa[N], son[N];
ll a[N], ans = 0LL, nowSum = 0LL, w[N], val[N]; struct Edge {
int to, nxt;
} e[N << ]; inline void add(int from, int to) {
e[++tot].to = to;
e[tot].nxt = head[from];
head[from] = tot;
} template <typename T>
inline void read(T &X) {
X = ;
char ch = ;
T op = ;
for(; ch > ''|| ch < ''; ch = getchar())
if(ch == '-') op = -;
for(; ch >= '' && ch <= ''; ch = getchar())
X = (X << ) + (X << ) + ch - ;
X *= op;
} void dfs1(int x, int fat, int depth) {
siz[x] = , fa[x] = fat, dep[x] = depth, val[x] = a[x];
int maxson = -;
for(int i = head[x]; i; i = e[i].nxt) {
int y = e[i].to;
if(y == fat) continue;
dfs1(y, x, depth + );
siz[x] += siz[y], val[x] += val[y];
if(siz[y] > maxson)
maxson = siz[y], son[x] = y;
}
} void dfs2(int x, int topf) {
w[id[x] = ++dfsc] = val[x], top[x] = topf;
if(!son[x]) return;
dfs2(son[x], topf);
for(int i = head[x]; i; i = e[i].nxt) {
int y = e[i].to;
if(y == fa[x] || y == son[x]) continue;
dfs2(y, y);
}
} namespace SegT {
ll s[N << ], tag[N << ]; #define lc p << 1
#define rc p << 1 | 1
#define mid ((l + r) >> 1) inline void up(int p) {
if(p) s[p] = s[lc] + s[rc];
} inline void down(int p, int l, int r) {
if(!tag[p]) return;
s[lc] += 1LL * (mid - l + ) * tag[p];
s[rc] += 1LL * (r - mid) * tag[p];
tag[lc] += tag[p], tag[rc] += tag[p];
tag[p] = 0LL;
} void build(int p, int l, int r) {
tag[p] = 0LL;
if(l == r) {
s[p] = w[l];
return;
} build(lc, l, mid);
build(rc, mid + , r);
up(p);
} void modify(int p, int l, int r, int x, int y, ll v) {
if(x <= l && y >= r) {
s[p] += 1LL * (r - l + ) * v;
tag[p] += v;
return;
} down(p, l, r);
if(x <= mid) modify(lc, l, mid, x, y, v);
if(y > mid) modify(rc, mid + , r, x, y, v);
up(p);
} ll qSum(int p, int l, int r, int x, int y) {
if(x <= l && y >= r) return s[p];
down(p, l, r); ll res = 0LL;
if(x <= mid) res += qSum(lc, l, mid, x, y);
if(y > mid) res += qSum(rc, mid + , r, x, y);
return res;
} } using namespace SegT; inline void mTree(int x) {
ll v, sum = 0LL, len = (ll)dep[x]; read(v);
v -= a[x], a[x] += v;
for(; x != ; x = fa[top[x]]) {
sum += qSum(, , n, id[top[x]], id[x]);
modify(, , n, id[top[x]], id[x], v);
}
ans += 2LL * v * sum + 1LL * v * v * len;
nowSum += v;
} inline ll qTree(int x) {
ll res = 0LL;
for(; x != ; x = fa[top[x]])
res += qSum(, , n, id[top[x]], id[x]);
return res;
} inline void solve(int x) {
ll k = (ll)dep[x], sum = qTree(x);
printf("%lld\n", ans + nowSum * ((k + ) * nowSum - * sum));
} int main() {
read(n), read(qn);
for(int x, y, i = ; i < n; i++) {
read(x), read(y);
add(x, y), add(y, x);
}
for(int i = ; i <= n; i++) read(a[i]); dfs1(, , );
dfs2(, );
build(, , n); /* for(int i = 1; i <= n; i++)
printf("%d ", dep[i]);
printf("\n");
for(int i = 1; i <= n; i++)
printf("%d ", top[i]);
printf("\n");
for(int i = 1; i <= n; i++)
printf("%d ", w[i]);
printf("\n"); */ for(int i = ; i <= n; i++) {
nowSum += a[i];
ans += val[i] * val[i];
}
// printf("%lld\n", ans); for(int op, x; qn--; ) {
read(op), read(x);
if(op == ) mTree(x);
else solve(x);
} return ;
}

Luogu 3676 小清新数据结构题的更多相关文章

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

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

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

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

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

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

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

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

  5. Luogu3676 小清新数据结构题 动态点分治

    传送门 换根类型的统计问题动态点分治都是很好做的. 设所有点的点权和为$sum$ 首先,我们先不考虑求$\sum\limits_i s_i^2$,先考虑如何在换根的情况下求$\sum\limits_i ...

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

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

  7. [luogu3676] 小清新数据结构题 [树链剖分+线段树]

    题面 传送门 思路 本来以为这道题可以LCT维护子树信息直接做的,后来发现这样会因为splay形态改变影响子树权值平方和,是splay本身的局限性导致的 所以只能另辟蹊径 首先,我们考虑询问点都在1的 ...

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

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

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

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

随机推荐

  1. MySQL学习之一数据库简介

    1.什么是数据库? 数据库(Database)是按照数据结构来组织.存储和管理数据的仓库,长期储存在计算机内.有组织的.可共享的数据集合. 数据库中的数据指的是以一定的数据模型组织.描述和储存在一起. ...

  2. HDFS常用的Java Api详解

    转自:http://blog.csdn.net/michaelwubo/article/details/50879832 一.使用Hadoop URL读取数据 package hadoop; impo ...

  3. Why getting this error “django.db.utils.OperationalError: (1050, ”Table 'someTable' already exists“)”

    0down votefavorite   I am getting error like django.db.utils.OperationalError: (1050, "Table 's ...

  4. 使用 MLCC 替代电解电容需要注意几点 (2018-07-23)

    使用 MLCC 替代电解电容需要注意几点 容量,MLCC 在高压时容量会降到标称的 30~50% 以下 1. MLCC 的 ESR 很低,比较适合高频 DCDC 输出. MLCC 会有压电效应,可能会 ...

  5. docker容器的服务发现:consul

    官网:https://www.consul.io 官网文档:https://www.consul.io/docs简介 consul是一个服务发现的组件,在docker世界中他比较流行,主要是consu ...

  6. Linux基础命令-系统时间

    Linux启动时从硬件读取日期和时间信息,读取完成以后,就不再与硬件相关联 Linux的两种时钟 系统时钟:由Linux内核通过CPU的工作频率进行的: date:显示系统时间 +%D +%F dat ...

  7. commandLink/commandButton/ajax backing bean action/listener method not invoked (转)

    Whenever an UICommand component fails to invoke the associated action method or an UIInputelement fa ...

  8. the virtual machine is configured for 64-bit guest operating systems

    Security--Virtualization--Inter(R) Virtualization Technolog 设置为enable 本机安装的是WIN 7 ,详细版本是:Windows 7 U ...

  9. codeforce 510C Fox And Names(拓扑排序)

    Fox And Names time limit per test 2 seconds memory limit per test 256 megabytes input standard input ...

  10. JAVA方法中的参数用final来修饰的效果

    很多人都说在JAVA中用final来修饰方法参数的原因是防止方法参数在调用时被篡改,其实也就是这个原因,但理解起来可能会有歧义,我们需要注意的是,在final修饰的方法参数中,如果修饰的是基本类型,那 ...