牛客挑战赛46 F

这篇博客深入探讨了如何利用离线处理和线段树的数据结构来解决求解路径上节点到根节点距离之和的问题。文章首先介绍了问题背景,并详细解释了线段树和最近公共祖先(LCA)的概念。接着,通过实例展示了如何将两者结合,实现高效计算。博主还提供了一段C++代码,用于离线处理和维护路径上节点到根节点距离的前缀和,以解答一系列查询。整个过程涉及到树的遍历、LCA查询优化以及线段树的更新和查询操作。
摘要由CSDN通过智能技术生成

可以很显然的发现,答案等于 ∑ d i s t i , r o o t − a l l ( l c a ( l , l + 1 , l + 2 , , , , r ) ) \sum{dist_{i,root}}-all(lca(l,l+1,l+2,,,,r)) disti,rootall(lca(l,l+1,l+2,,,,r))其中
我们可以使用线段树取 [ l , r ] l c a [l,r]lca [l,r]lca
每一个点到根的和,我们考虑先离线,再 a c c e s s access access过程。每一次打通一条链,就要把这条链上,已经遍历过的点到该链的链头的距离给剪掉。在随便使用一个数据结构维护前缀和单点修改即可。因为离线,存储R,每一次access后,一定是向后满足条件的,所以每一次相当于询问前缀是否可行。

#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<climits>
#include<stack>
#include<vector>
#include<queue>
#include<set>
#include<bitset>
#include<map>
//#include<regex>
#include<cstdio>
#include <iomanip>
#include<unordered_map>
#pragma GCC diagnostic error "-std=c++11"
#pragma GCC optimize("-fdelete-null-pointer-checks,inline-functions-called-once,-funsafe-loop-optimizations,-fexpensive-optimizations,-foptimize-sibling-calls,-ftree-switch-conversion,-finline-small-functions,inline-small-functions,-frerun-cse-after-loop,-fhoist-adjacent-loads,-findirect-inlining,-freorder-functions,no-stack-protector,-fpartial-inlining,-fsched-interblock,-fcse-follow-jumps,-fcse-skip-blocks,-falign-functions,-fstrict-overflow,-fstrict-aliasing,-fschedule-insns2,-ftree-tail-merge,inline-functions,-fschedule-insns,-freorder-blocks,-fwhole-program,-funroll-loops,-fthread-jumps,-fcrossjumping,-fcaller-saves,-fdevirtualize,-falign-labels,-falign-loops,-falign-jumps,unroll-loops,-fsched-spec,-ffast-math,Ofast,inline,-fgcse,-fgcse-lm,-fipa-sra,-ftree-pre,-ftree-vrp,-fpeephole2",3)
#pragma GCC target("avx","sse2")
#define up(i,a,b)  for(int i=a;i<b;i++)
#define dw(i,a,b)  for(int i=a;i>b;i--)
#define upd(i,a,b) for(int i=a;i<=b;i++)
#define dwd(i,a,b) for(int i=a;i>=b;i--)
//#define local
typedef long long ll;
typedef unsigned long long ull;
const double esp = 1e-6;
const double pi = acos(-1.0);
const int INF = 0x3f3f3f3f;
const int inf = 1e9;
using namespace std;
ll read()
{
	char ch = getchar(); ll x = 0, f = 1;
	while (ch<'0' || ch>'9') { if (ch == '-')f = -1; ch = getchar(); }
	while (ch >= '0' && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); }
	return x * f;
}
typedef pair<int, int> pir;
#define lson l,mid,root<<1
#define rson mid+1,r,root<<1|1
#define lrt root<<1
#define rrt root<<1|1
const int N = 2e5 + 10;
int n, Q;
vector<int>vec[N];
vector<pir>ques[N];
int dep[N * 2], dfn[N * 2], rk[N * 2], st, dp[N * 2][30];
int ans[N];
struct sgt {
	int sum[N << 2];
	void pushup(int root) {
		sum[root] = sum[lrt] + sum[rrt];
	}
	void update(int l, int r, int root, int pos, int val) {
		if (l == r) {
			sum[root] += val; return;
		}
		int mid = (l + r) >> 1;
		if (pos <= mid)update(lson, pos, val);
		else update(rson, pos, val);
		pushup(root);
	}
	int query(int l, int r, int root, int lf, int rt) {
		if (lf > rt)return 0;
		if (lf <= l && r <= rt) { return sum[root]; }
		int mid = (l + r) >> 1;
		int ans = 0;
		if (lf <= mid)ans += query(lson, lf, rt);
		if (rt > mid)ans += query(rson, lf, rt);
		return ans;
	}
}T;
struct LCT {
	int ch[N][2], par[N], lz[N], val[N], sz[N];
	int ident(int rt, int fa) {
		return ch[fa][1] == rt;
	}
	void connect(int rt, int fa, int son) {
		par[rt] = fa;
		ch[fa][son] = rt;
	}
	bool isroot(int rt) {
		int f = par[rt];
		return ch[f][1] != rt && ch[f][0] != rt;
	}
	void rotate(int rt) {
		int f = par[rt]; int ff = par[f]; int k = ident(rt, f);
		connect(ch[rt][k ^ 1], f, k);
		par[rt] = ff;
		if (!isroot(f))ch[ff][ident(f, ff)] = rt;
		connect(f, rt, k ^ 1);
		pushup(f); pushup(rt);
	}
	void pushup(int rt) {
		sz[rt] = sz[ch[rt][0]] + sz[ch[rt][1]] + 1;
	}
	void pushdown(int rt) {
		if (lz[rt]) {
			int ls = ch[rt][0];
			int rs = ch[rt][1];
			if (ls)val[ls] = lz[ls] = lz[rt];
			if (rs)val[rs] = lz[rs] = lz[rt];
			lz[rt] = 0;
		}
	}
	void pushall(int rt) {
		if (!isroot(rt))pushall(par[rt]);
		pushdown(rt);
	}
	void splay(int x) {
		pushall(x);
		while (!isroot(x)) {
			int f = par[x]; int ff = par[f];
			if (!isroot(f))ident(f, ff) ^ ident(x, f) ? rotate(x) : rotate(f);
			rotate(x);
		}
	}
	void access(int x, int col) {
		int y;
		for (y = 0; x; y = x, x = par[x]) {
			splay(x);
			if (val[x])
				T.update(1, n, 1, val[x], -sz[ch[x][0]] - 1);
			T.update(1, n, 1, col, sz[ch[x][0]] + 1);
			//cout <<val[x]<<" "<< T.query(1, n, 1, 1, val[x]) << " ";
			ch[x][1] = y;
			pushup(x);
		}
		val[y] = lz[y] = col;
	}
}lct;
void dfs1(int u, int fa, int d) {
	lct.par[u] = fa;
	dfn[++st] = u; dep[st] = d;
	rk[u] = st;
	for (auto k : vec[u]) {
		if (k == fa)continue;
		dfs1(k, u, d + 1);
		dfn[++st] = u;
		dep[st] = d;
		rk[u] = st;
	}
}
void initst() {
	upd(i, 0, 2 * n)dp[i][0] = i;
	upd(j, 1, 30) {
		for (int i = 1; i + (1 << j) - 1 <= 2 * n; i++) {
			int t1 = dp[i][j - 1]; int t2 = dp[i + (1 << (j - 1))][j - 1];
			dp[i][j] = dep[t1] < dep[t2] ? t1 : t2;
		}
	}
}
int lca(int x, int y) {
	x = rk[x], y = rk[y];
	if (x > y)swap(x, y);
	int k = int(log2(y - x + 1));
	int t1 = dp[x][k]; int t2 = dp[y - (1 << k) + 1][k];
	return dep[t1] < dep[t2] ? dfn[t1] : dfn[t2];
}
struct LCAT {
	int LCA[N << 2];
	void pushup(int root) {
		LCA[root] = lca(LCA[lrt], LCA[rrt]);
	}
	void build(int l, int r, int root) {
		if (l == r) {
			LCA[root] = l; return;
		}
		int mid = (l + r) >> 1;
		build(lson); build(rson); pushup(root);
	}
	int query(int l, int r, int root, int lf, int rt) {
		if (lf <= l && r <= rt) {
			return LCA[root];
		}
		int mid = (l + r) >> 1;
		int temp = -1;
		if (lf <= mid)temp = query(lson, lf, rt);
		if (rt > mid) {
			if (temp == -1)temp = query(rson, lf, rt);
			else temp = lca(temp, query(rson, lf, rt));
		}
		return temp;
	}
}LCAT;
int main() {
	n = read(); Q = read();
	int u, v;
	upd(i, 1, n - 1) {
		u = read(), v = read();
		vec[u].push_back(v);
		vec[v].push_back(u);
	}
	upd(i, 1, Q) {
		u = read(), v = read();
		ques[v].push_back({ u,i });
	}
	dfs1(1, 0, 0);
	initst();
	upd(i, 1, n) {
		 lct.sz[i] = 1;
	}
	LCAT.build(1, n, 1);
	//cout << LCAT.query(1, n, 1, 1, 2);
	upd(i, 1, n) {
		lct.access(i, i);
		cout << T.query(1, n, 1, 1, i);
		//upd(j, 1, i) {
		//	cout << T.query(1, n, 1, 1, j) << "  ";
		//}cout << endl;
		for (auto k : ques[i]) {
			ans[k.second] = T.query(1, n, 1, k.first, i) - dep[rk[LCAT.query(1, n, 1, k.first, i)]] - 1;
		}
	}
	upd(i, 1, Q)printf("%d\n", ans[i]);
	return 0;
}
微信小程序毕业设计期末大作业项目源码 微信小程序毕业设计期末大作业项目源码 微信小程序毕业设计期末大作业项目源码 微信小程序毕业设计期末大作业项目源码 微信小程序毕业设计期末大作业项目源码 微信小程序毕业设计期末大作业项目源码 微信小程序毕业设计期末大作业项目源码 微信小程序毕业设计期末大作业项目源码 微信小程序毕业设计期末大作业项目源码 微信小程序毕业设计期末大作业项目源码 微信小程序毕业设计期末大作业项目源码 微信小程序毕业设计期末大作业项目源码 微信小程序毕业设计期末大作业项目源码 微信小程序毕业设计期末大作业项目源码 微信小程序毕业设计期末大作业项目源码 微信小程序毕业设计期末大作业项目源码 微信小程序毕业设计期末大作业项目源码 微信小程序毕业设计期末大作业项目源码 微信小程序毕业设计期末大作业项目源码 微信小程序毕业设计期末大作业项目源码 微信小程序毕业设计期末大作业项目源码 微信小程序毕业设计期末大作业项目源码 微信小程序毕业设计期末大作业项目源码 微信小程序毕业设计期末大作业项目源码 微信小程序毕业设计期末大作业项目源码 微信小程序毕业设计期末大作业项目源码 微信小程序毕业设计期末大作业项目源码 微信小程序毕业设计期末大作业项目源码 微信小程序毕业设计期末大作业项目源码 微信小程序毕业设计期末大作业项目源码 微信小程序毕业设计期末大作业项目源码 微信小程序毕业设计期末大作业项目源码
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值