链接:I love tree
题意:
给一棵树 , 初始所有点的点权为 0 ,现有两种操作 :
- 给出 a , b,把a 到 b路径上的点依次加上 1 ^ 2 , 2 ^ 2 , 3 ^ 2。
- 给出一个 a 求点 a 的权值。
思路:
- 如果是一个普通的数组进行上述修改操作 , 我们有两种方法 , 观察上述操作,发现加上的值差分后是一个等差数列 , 所以我们把原数组差分,把操作数也差分一下,就变成区间维护一个等差数列,一个点的答案就是前缀和。但是这是在树上 , 感觉就不太好操作了,多校的题解说是要分块。
- 另外一种做法就是把加的平方数变成点编号的平方,相当于做一个区间 + 1 , 最后算答案的时候用这个值乘编号的平方 。 举个例子 如果当前操作区间为 [l , r] , 区间中当前点编号为 id , 那么这个点加的就是 (id - (l - 1) ) ^ 2 ,展开后发现需要加的 id ^ 2之和当前点的编号有关 , 所以这里可以用区间 + 1 维护。- 2 * id * (l - 1)所以就是区间加 (l - 1),最后的值乘 -2 * id。这里的(l - 1)对整个要加区间都是定值。所以最后开三个线段树维护这三个值就好了。
- 最后还要注意对于一条链 (a , b)正着加和反着加是不一样的。还有在树上对一条链加的时候会被分成log条小链,而这些小链的编号不一定是连续的 , 所以在加的时候要看当前已经加了多少个点了,上述的 l 时会有变化。
代码:
#include <iostream>
#include <cstdio>
#include <queue>
#include <math.h>
#include <map>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
const int maxn = 2e6 + 7;
ll sum[4][maxn << 2],lazy[4][maxn << 2],val[maxn];
int n;
int depth[maxn],siz[maxn],fa[maxn],son[maxn],cnt,id[maxn],tot[maxn],num,head[maxn<<1];
struct node{
int u,v,next;
}e[maxn<<1];
void add(int u,int v){
e[++num].next=head[u];
e[num].v=v;
head[u]=num;
}
void dfs1(int u,int pre,int dep){
depth[u]=dep; siz[u]=1; fa[u]=pre;
for(int i=head[u]; i; i=e[i].next){
int to = e[i].v;
if( to == pre) continue;
dfs1(to,u,dep+1);
siz[u]+=siz[to];
if(siz[to]>siz[son[u]]) son[u]=to; //更新重儿子
}
}
void dfs2(int u,int t){
id[u]=++cnt; //赋予新的序列号
tot[u]=t; //重边顶点
if(son[u]) dfs2(son[u],t); //优先对重链编号
for(int i=head[u];i;i=e[i].next){
int to=e[i].v;
if(to!=son[u]&&to!=fa[u]) //跳过重儿子和父节点
dfs2(to,to); //非重儿子的 tot是本身
}
}
int lca(int x,int y){
while(tot[x]!=tot[y]){
if(depth[tot[x]]<depth[tot[y]]) swap(x,y);
x=fa[tot[x]];
}
if(depth[x]>depth[y]) return y;
return x;
}
void pushdown(int id , int rt, int l, int r){
int m = (l + r) >> 1;
if(lazy[id][rt]){
lazy[id][rt << 1] += lazy[id][rt];
lazy[id][rt << 1 | 1] += lazy[id][rt];
sum[id][rt << 1] += lazy[id][rt] * (m - l + 1);
sum[id][rt << 1 | 1] += lazy[id][rt] * (r - m);
lazy[id][rt]=0;
}
}
void update(int id , int L, int R, ll v, int l, int r, int rt){
if(L <= l && R >= r){
sum[id][rt] += v * (r - l + 1);
lazy[id][rt] += v;
return ;
}
pushdown(id , rt , l , r);
int m = (l + r) >> 1;
if(L <= m) update(id , L , R , v , l , m , rt << 1);
if(R > m) update(id , L , R , v , m + 1, r , rt << 1 | 1);
sum[id][rt] = sum[id][rt << 1] + sum[id][rt << 1 | 1];
}
ll query(int id , int pos , int l,int r,int rt){
ll s = 0;
if(l == r){
return sum[id][rt];
}
pushdown(id , rt , l , r);
int m = (l + r) >> 1;
if(pos <= m) s += query(id , pos , l , m , rt << 1);
if(pos > m) s += query(id , pos , m + 1 , r , rt << 1 | 1);
return s;
}
void add_v(int x,int y , int len){
int l = 1 , r = len;
while(tot[x] != tot[y]){
if(depth [tot[x]] > depth[tot[y]]){
ll val = id[tot[x]] - l;
update(1 , id[tot[x]] , id[x] , 1 , 1 , n , 1);
update(2 , id[tot[x]] , id[x] , val , 1 , n , 1);
update(3 , id[tot[x]] , id[x] , val * val ,1 , n , 1);
l += depth[x] - depth[tot[x]] + 1;
x = fa [tot[x]];
}
else{
ll val = id[tot[y]] + r;
update(1 , id[tot[y]] , id[y] , 1 , 1 , n , 1);
update(2 , id[tot[y]] , id[y] , val , 1 , n , 1);
update(3 , id[tot[y]] , id[y] , val * val ,1 , n , 1);
r -= depth[y] - depth[tot[y]] + 1;
y = fa [tot[y]];
}
}
if(depth[x] < depth[y]){
ll val = id[x] - l;
update(1 , id[x] , id[y] , 1 , 1 , n , 1);
update(2 , id[x] , id[y] , val , 1 , n , 1);
update(3 , id[x] , id[y] , val * val ,1 , n , 1);
}
else{
ll val = id[y] + r;
update(1 , id[y] , id[x] , 1 , 1 , n , 1);
update(2 , id[y] , id[x] , val , 1 , n , 1);
update(3 , id[y] , id[x] , val * val ,1 , n , 1);
}
}
int main() {
scanf("%d",&n);
for(int i = 1 , u , v; i < n; i ++){
scanf("%d%d",&u,&v);
add(u , v);
add(v , u);
}
dfs1(1, -1, 0);
dfs2(1 , 1);
int q;
scanf("%d",&q);
int op , l , r;
while(q--){
scanf("%d",&op);
if(op == 1){
scanf("%d%d",&l,&r);
int lc = lca(l , r);
add_v(l , r , depth[l] + depth[r] - 2 * depth[lc] + 1);
}
else{
scanf("%d",&l);
l = id[l];
ll ans1 = query(1 , l , 1 , n , 1),ans2 = query(2 , l , 1 , n , 1),ans3 = query(3 , l , 1 , n , 1);
printf ("%lld\n",ans1 * l * l - 2 * ans2 * l + ans3);
}
}
return 0;
}
/*
5
1 2
1 3
3 4
3 5
1000
1 4 5
2 5
*/