树链剖分 ---- 2021杭电多校 1002 I love tree[详解]
题目链接
题目大意:
就是给你一颗树
树上每个点的初始权值为000
现在有两个操作
- <1,a,b><1,a,b><1,a,b>对于aaa到bbb路径上所有点加上到aaa的距离的平方和
- <2,a><2,a><2,a>询问aaa点的权值
解题思路:
对于树链上的修改问题我们很容易想到树链剖分
但是怎么对于每个点距离aaa的距离不一样那么累加的权值也不一样怎么办?
首先我们知道对于树链剖分上面的线段树是用时间戳dfn时间戳dfn时间戳dfn进行区间划分的,那么我们就可以往dfndfndfn上面想
我们观察一下下面的图片就是<a,b><a,b><a,b>的路径上面有两种情况a−>lcaa->lcaa−>lca和lca−>blca->blca−>b
现在假设我们要得到某个点得值那么只能是靠dfn[x]dfn[x]dfn[x]去计算答案
distance(a,x)2=(dfn[x]−?)2distance(a,x)^2=(dfn[x]-?)^2distance(a,x)2=(dfn[x]−?)2现在就是要求这个问号是什么?
对于a−>lcaa->lcaa−>lca的情况我们知道对于[dfn[top[x]],dfn[x]][dfn[top[x]],dfn[x]][dfn[top[x]],dfn[x]]这是一段连续的区间
对于里面的任意一个点x′x'x′我们可以(dfn[x′]−dfn[x])2(dfn[x']-dfn[x])^2(dfn[x′]−dfn[x])2
但是我们知道树链剖分是一段一段的跳的那么上面的那个式子还得加上a和x之间有多少个点a和x之间有多少个点a和x之间有多少个点?
但是注意(dfn[x′]−dfn[x])2(dfn[x']-dfn[x])^2(dfn[x′]−dfn[x])2里面是负数所以你要减掉点数
(dfn[x′]−dfn[x]−point′snumbrebetweenxanda)2(dfn[x']-dfn[x]-point's \; numbre\;between\;x\;and\;a)^2(dfn[x′]−dfn[x]−point′snumbrebetweenxanda)2
(dfn[x′]−(dfn[x]+point′snumbrebetweenxanda))2(dfn[x']-(dfn[x]+point's \; numbre\;between\;x\;and\;a))^2(dfn[x′]−(dfn[x]+point′snumbrebetweenxanda))2
num=(dfn[x]+point′snumbrebetweenxanda)num=(dfn[x]+point's \; numbre\;between\;x\;and\;a)num=(dfn[x]+point′snumbrebetweenxanda)
(dfn[x′]−num)2=dfn[x′]2−2∗num∗dfn[x′]+num2(dfn[x']-num)^2=dfn[x']^2-2*num*dfn[x']+num^2(dfn[x′]−num)2=dfn[x′]2−2∗num∗dfn[x′]+num2
那么我们就可以用3个线段树去维护这3项的系数1,2∗num,num21,2*num,num^21,2∗num,num2因为对于同一个区间numnumnum
是一样的
对于b−>lcab->lcab−>lca的情况这里是(dfn[x′]−dfn[top[x′]])2(dfn[x']-dfn[top[x']])^2(dfn[x′]−dfn[top[x′]])2注意这里面dfn[x′]−dfn[top[x′]]dfn[x']-dfn[top[x']]dfn[x′]−dfn[top[x′]]是大于0的
那么和上面同理但是计算距离的时候你要算出top[x′]到a的距离top[x']到a的距离top[x′]到a的距离
AC代码:
#include <bits/stdc++.h>
#define mid ((l + r) >> 1)
#define Lson rt << 1, l , mid
#define Rson rt << 1|1, mid + 1, r
#define ms(a,al) memset(a,al,sizeof(a))
#define log2(a) log(a)/log(2)
#define lowbit(x) ((-x) & x)
#define IOS std::ios::sync_with_stdio(0); cin.tie(0); cout.tie(0)
#define INF 0x3f3f3f3f
#define LLF 0x3f3f3f3f3f3f3f3f
#define f first
#define s second
#define endl '\n'
using namespace std;
const int N = 2e6 + 10, mod = 1e9 + 9;
const int maxn = 500010;
const long double eps = 1e-5;
const int EPS = 500 * 500;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> PII;
typedef pair<ll,ll> PLL;
typedef pair<double,double> PDD;
template<typename T> void read(T &x)
{x = 0;char ch = getchar();ll f = 1;while(!isdigit(ch)){if(ch == '-')f*=-1;ch=getchar();}while(isdigit(ch)){x = x*10+ch-48;ch=getchar();}x*=f;
}
template<typename T, typename... Args> void read(T &first, Args& ... args)
{read(first);read(args...);
}
int T;
int n, m;
struct node {int to, next;
}e[N];
int head[N], cnt;
inline void add(int from, int to) {e[cnt] = {to,head[from]};head[from] = cnt ++;
}
//...............................
int fa[N], dep[N], siz[N], son[N];
inline void dfs1(int u, int f) {fa[u] = f, dep[u] = dep[f] + 1, siz[u] = 1;int max_siz = -1;for(int i = head[u]; ~i; i = e[i].next) {int v = e[i].to;if(v == f) continue;dfs1(v,u);siz[u] += siz[v];if(siz[v] > max_siz) {son[u] = v;max_siz = siz[v];} }
}ll tim, dfn[N], top[N];
inline void dfs2(int u, int t) {dfn[u] = ++ tim, top[u] = t;if(!son[u]) return;dfs2(son[u],t);for(int i = head[u]; ~i; i = e[i].next) {int v = e[i].to;if(v == fa[u] || v == son[u]) continue;dfs2(v,v);}
}
struct Segtree {ll tr[maxn], lazy[maxn];void add(int rt , int l, int r, int posL, int posR, ll val) {if(posL <= l && posR >= r) {tr[rt] += val;lazy[rt] += val;return;}if(posL <= mid) add(Lson,posL,posR,val);if(posR > mid) add(Rson,posL,posR,val);}inline void pushdown(int rt) {if(lazy[rt]) {lazy[rt << 1] += lazy[rt];lazy[rt << 1|1] += lazy[rt];tr[rt << 1] += lazy[rt];tr[rt << 1|1] += lazy[rt];lazy[rt] = 0;}}ll ask(int rt, int l, int r, int pos) {if(l == r) return tr[rt];pushdown(rt);if(pos <= mid) return ask(Lson,pos);else return ask(Rson,pos);}
}seg[3];int LCA(int x,int y)
{for(;top[x]!=top[y];dep[top[x]]>dep[top[y]]?x=fa[top[x]]:y=fa[top[y]]);return dep[x]<dep[y]?x:y;
}inline void tree_change(int a, int b) {int lca = LCA(a,b);int len = dep[a] + dep[b] - 2 * dep[lca] + 1;int up = 1, down = 0;// cout << top[a] << " " << top[b] <<endl;while(top[a] != top[b]) {if(dep[top[a]] > dep[top[b]]) {ll k = dfn[a] + up;// cout << k << endl;seg[0].add(1,1,n,dfn[top[a]],dfn[a],k*k);seg[1].add(1,1,n,dfn[top[a]],dfn[a],2*k);seg[2].add(1,1,n,dfn[top[a]],dfn[a],1);up += dep[a] - dep[top[a]] + 1;a = fa[top[a]];} else {ll k = dfn[top[b]] - 1 - (len - (dep[b] - dep[top[b]] + 1) - down);//后面计算距离seg[0].add(1,1,n,dfn[top[b]],dfn[b],k*k);seg[1].add(1,1,n,dfn[top[b]],dfn[b],2*k);seg[2].add(1,1,n,dfn[top[b]],dfn[b],1);down += dep[b] - dep[top[b]] + 1;b = fa[top[b]];}}if(dep[a] > dep[b]) {ll k = dfn[a] + up;seg[0].add(1,1,n,dfn[b],dfn[a],k*k);seg[1].add(1,1,n,dfn[b],dfn[a],2*k);seg[2].add(1,1,n,dfn[b],dfn[a],1); } else {ll k = dfn[a] - 1 - (len - (dep[b] - dep[a] + 1) - down);// cout << k <<endl;seg[0].add(1,1,n,dfn[a],dfn[b],k*k);seg[1].add(1,1,n,dfn[a],dfn[b],2*k);seg[2].add(1,1,n,dfn[a],dfn[b],1); }
}inline ll ask(int pos) {return 1ll * dfn[pos] * dfn[pos] * seg[2].ask(1,1,n,dfn[pos]) - 1ll * dfn[pos] * seg[1].ask(1,1,n,dfn[pos]) + 1ll * seg[0].ask(1,1,n,dfn[pos]);
}int main() {//IOS;ms(head,-1);cin >> n;for(int i = 1; i < n; ++ i) {int u, v;cin >> u >> v;add(u,v);add(v,u);}dfs1(1,0);dfs2(1,0);// for(int i = 1; i <= n; ++ i) cout << dfn[i] << endl;int m;cin >> m;while(m --) {int op;cin >> op;if(op == 1) {int a, b;cin >> a >> b;tree_change(a,b);} else {int pos;cin >> pos;cout << ask(pos) << endl;}}return 0;
}
/*9
2 1
3 1
4 2
5 2
6 4
7 3
8 3
9 3
2
1 8 4
2 15
2 1
3 2
4 1
5 4
2
1 1 3
2 117
1 1 1
2 1
1 4 3
2 1
1 2 4
2 1
1 1 3
2 1
1 2 4
2 1
1 4 1
2 1
1 3 2
2 4
1 4 5
2 2
2 2*/
树链剖分 ---- 2021杭电多校 1002 I love tree[详解]相关推荐
- 2021杭电多校补题——第一场
2021杭电多校补题--第一场 文章目录 Mod, Or and Everything Rocket land(待补) Puzzle loop(待补) Another thief in a Shop( ...
- 【2021杭电多校赛】2021“MINIEYE杯”中国大学生算法设计超级联赛(2)签到题5题
Solved Pro.ID Title Ratio(Accepted / Submitted) 1001 I love cube 26.49%(880/3322)(递推) 1002 I love tr ...
- 2021杭电多校第八场补题
比赛传送门:Contest Problem List (hdu.edu.cn) 1006)GCD Game 题目翻译:爱丽丝和鲍勃正在玩游戏. 他们轮流操作.有n个数字,a1,a2,...,an.每次 ...
- 【2021杭电多校赛】2021“MINIEYE杯”中国大学生算法设计超级联赛(3)签到题3题
2021"MINIEYE杯"中国大学生算法设计超级联赛(3) Start Time : 2021-07-27 12:00:00 End Time : 2021-07-27 17:0 ...
- 【2021杭电多校赛】2021“MINIEYE杯”中国大学生算法设计超级联赛(1)签到题15869
2021"MINIEYE杯"中国大学生算法设计超级联赛(1) Start Time : 2021-07-20 12:10:00 End Time : 2021-07-20 17:1 ...
- 【2021杭电多校赛】2021“MINIEYE杯”中国大学生算法设计超级联赛(8)签到题5题
Current Server Time : 2021-08-12 17:17:29 Solved Pro.ID Title Ratio(Accepted / Submitted) 1001 X-lik ...
- 【2021杭电多校赛】2021“MINIEYE杯”中国大学生算法设计超级联赛(4)签到题4题
Solved Pro.ID Title Ratio(Accepted / Submitted) 1001 Calculus 23.59%(852/3611) (数学,签到,结论) 1002 Kanad ...
- 【2021杭电多校赛】2021“MINIEYE杯”中国大学生算法设计超级联赛(8)
1006 GCD Game (博弈论,nim游戏,质因子个数) 题意:有n个数a1,a2....an两个人玩游戏,Alice先动,Bob后动每次可以将一个数变为他的因子,直到不能动就输了. 题解:将问 ...
- 2021杭电多校补题(3)
1009题目链接 设 fijkf_{ijk}fijk 表示从 (1,1) 走到 (i,j),一路上收集了 k 个钻石时,钻石的单价最高能涨到多少,则 ans = max(k × f n,n,k ). ...
最新文章
- RDKit:基于支持向量回归预测logP
- Springboot swagger2教程
- excel中最常用的30个函数_最常用日期函数汇总excel函数大全收藏篇
- 用Advanced Installer制作DotNetBar for Windows Forms 12.0.0.1_冰河之刃重打包版详解
- 写CSDN插入图片一直无法显示?
- 清华硕士面试阿里惨遭淘汰,网友:并非所有都是强者,也要看人
- va_list 简介
- linux启动过程中内核拷贝,轻松识破linux内核启动过程中的“”套路“”
- 简单人物画像_天天谈【用户画像】95%的人根本不知道自己在说什么
- 【MySQL】数据库事务处理---MySQL
- 自动给神经网络找bug,Google发布TensorFuzz
- DFS和BFS算法介绍
- Ubuntu下同时安装caffe和tensorflow
- 【转】HTML标签大全
- java多网卡组播,多网卡 组播
- proteus仿真微型计算机,微机原理与接口技术——基于8086和Proteus仿真(第3版)...
- 使用python内置函数进行常规API接口调用
- 一个星期内怎样学会微信公众号运营?
- html多张图片合在一块,多张照片怎么拼在一起?10张以上多图拼图方法 超简单! (全文)...
- 大商创x支持mysql版本_【大商创安装】大商创X宝塔面板安装配置简述