首页 > 其他分享 >【树论典题。】P6071 『MdOI R1』Treequery

【树论典题。】P6071 『MdOI R1』Treequery

时间:2023-08-08 19:22:23浏览次数:49  
标签:sz R1 anc int P6071 树论 lst dfn top

前言:

输了,被水杯提醒我一直很失败。

正片:

简要题意

求 \([l, r] \to p\) 的路径的交的边权和。

Solution:\(O(n \log^2 n)\) 巨大分讨做法。

考虑分类讨论。

其一,\(p\) 根本就不属于路径上的点,这个求区间 LCA 可以解决 \(p \to anc_{[l, r]}\)

其二,\(p\) 是 \(anc_{l, r}\) 的祖先,显然,还是上面那个。

其三,\(p\) 子树内有 \([l, r]\) 的点,直接为 0 即可,因为这样是没有交的。

其四,\(p \in anc_{l, r}\) 但不属于三,这个考虑倍增,求一个祖先满足三的情况即可。

这些全部都需要子树与区间交的技术,这个直接考虑二维数点,固定编号一维主席树数点即可,这个就是狼人。

#include <bits/stdc++.h>
#define rep(i, l, r) for (int i = l; i <= r; i ++)
#define per(i, r, l) for (int i = r; i >= l; i --)
#define ll long long

// 出题人小黑子树脂 66
using namespace std;

const int _ = 2e5 + 5;

struct EDGE { int y, z; } ;
vector <EDGE> e[_];
int n, q, dfc;
int pa[_][20], son[_], dis[_], dep[_], dfn[_], sz[_], top[_];
int lg[_], st[_][20];
void dfs1 (int x, int fa) {
	dep[x] = dep[fa] + 1, sz[x] = 1;
	pa[x][0] = fa;
	rep(i, 1, 19) pa[x][i] = pa[pa[x][i - 1]][i - 1];
	for (auto & [y, z] : e[x]) {
		if (y == fa) continue ;
		dis[y] = dis[x] + z,
		dfs1(y, x), sz[x] += sz[y];
		if (sz[son[x]] < sz[y]) son[x] = y;
	}
}
void dfs2 (int x, int fa, int anc) {
	dfn[x] = ++ dfc, top[x] = anc;
	if (son[x]) dfs2(son[x], x, anc);
	for (auto & [y, z] : e[x])
		if (y != fa && y != son[x]) dfs2(y, x, y);
}
int queryLCA (int x, int y) {
	while (top[x] != top[y]) {
		if (dep[top[x]] < dep[top[y]]) swap(x, y);
		x = pa[top[x]][0];
	}
	return dep[x] < dep[y] ? x : y;
}
int RangeLCA (int l, int r) {
	int k = lg[r - l + 1];
	return queryLCA(st[l][k], st[r - (1 << k) + 1][k]);
}

int rt[_], tot;
namespace tr {
	struct node {
		int lc, rc, s;
	} t[_ * 25];
	void modify (int & x, int y, int l, int r, int k) {
		x = ++ tot, t[x] = t[y], t[x].s ++;
		if (l == r) return ;
		int mid = (l + r) >> 1;
		if (k <= mid) modify(t[x].lc, t[y].lc, l, mid, k);
		else modify(t[x].rc, t[y].rc, mid + 1, r, k);
	}
	int query (int x, int l, int r, int ql, int qr) {
		if (!x) return 0;
		if (ql <= l && r <= qr) return t[x].s;
		int mid = (l + r) >> 1, ret = 0;
		if (ql <= mid) ret += query(t[x].lc, l, mid, ql, qr);
		if (qr > mid) ret += query(t[x].rc, mid + 1, r, ql, qr);
		return ret;
	}
	int insec (int x, int ql, int qr) {
		return query(rt[qr], 1, n, dfn[x], dfn[x] + sz[x] - 1) -
			   query(rt[ql - 1], 1, n, dfn[x], dfn[x] + sz[x] - 1);
	}
}
void build () {
	dfs1(1, 1), dfs2(1, 0, 1), lg[0] = -1;
	rep(i, 1, n) lg[i] = lg[i >> 1] + 1, st[i][0] = i;
	rep(k, 1, 19) rep(i, 1, n - (1 << k) + 1) 
	st[i][k] = queryLCA(st[i][k - 1], st[i + (1 << k - 1)][k - 1]);
	rep(x, 1, n) tr::modify(rt[x], rt[x - 1], 1, n, dfn[x]);
}
int dist (int x, int y) { return dis[x] + dis[y] - dis[queryLCA(x, y)] * 2; }
int findanc (int x, int l, int r) {
	int p;

	for (int i = 19; i >= 0; i --) {
		int p = pa[x][i];
//		cout << " " << p;
//		if (! p) continue ;
		
		if (! tr::insec(p, l, r)) x = p;
	}
	return pa[x][0];
}
#define bel(x, y) (dfn[x] >= dfn[y] && dfn[x] < sz[y] + dfn[y])
int main () {
	cin >> n >> q;
	rep(i, 1, n - 1) {
		int x, y, z;
		scanf("%d%d%d", & x, & y, & z);
		e[x].push_back({y, z}), e[y].push_back({x, z});
	}
	build();
	int p, l, r, lst = 0;
	while(q --) {
		scanf("%d%d%d", & p, & l, & r);
		p ^= lst, l ^= lst, r ^= lst;
		int anc = RangeLCA(l, r),
			cnt = tr::insec(p, l, r);
		if (bel(anc, p) || !bel(p, anc)) lst = dist(p, anc);
		else if (cnt) lst = 0;
		else {
			int t = findanc(p, l, r);
			lst = dist(p, t);
		}
//		cout << endl;
		printf("%d\n", lst);
	}
	return 0;
}

标签:sz,R1,anc,int,P6071,树论,lst,dfn,top
From: https://www.cnblogs.com/Custlo/p/17615188.html

相关文章

  • Ext Designer1.0试用手记
         Ext官网在4月22日推出了ExtDesigner1.0正式版,该版本可以试用14天。下面就是笔者的试用过程。   安装过程很简单,在这里就不赘述了。   软件运行后,将出现一个下图所示的注册窗口:      这里需要一个官网论坛帐号。   注册后,将显示以下窗口:    ......
  • P9451 [ZSHOI-R1] 新概念报数 题解
    满足\(\operatorname{popcount}(x)<3\)的数实际上很少,直接把所有这些数扔到set里面,询问就返回set中\(x\)的下一个元素即可。记得开longlong。set内的元素数量是\(\log^2w\),所以复杂度是\(\mathcalO(\log^2w\log\log^2w+T\log\log^2w)=\mathcalO(\log^2w\log\logw......
  • 7.27 day4 树论
    悲报:335->220战绩:100+100+20+0T1求子树sizeT2通过大眼观察严谨的证明后,我们发现\(x_i\)是\(x_i+1\)的祖先的概率和\(x_i+1\)具体是什么无关:我们令\(x_i+1\)一直跳父亲,直到编号小于等于\(x_i\)的那一次。因为父亲是等概率选取的,所以概率就是\(\frac{1}{x_i}\)......
  • JProfiler激活码分享最新可用jprofiler13许可证密钥
    JProfiler是一款专业的Java应用程序性能分析工具,可帮助开发人员识别和解决Java应用程序中的性能问题。JProfiler支持JavaSE、JavaEE和Android平台,提供了多种分析选项,包括CPU分析、内存分析和线程分析等。JProfiler激活码获取 使用JProfiler,开发人员可以实时查看Java应用程......
  • P7333 [JRKSJ R1] JFCA 题解
    前言传送门blog思路首先看数据范围$10^5$,$O(n\log_2n)$可以过,自然想到二分。二分具有单调性,那么如何确保整个$a$序列按顺序排列呢?我们可以使用st表维护区间最大值,如果在这个距离中已经有了$a_i\geb_j$那么最大值一定指向的是新加入进来的那个值,否则在之前二分就......
  • P9451 [ZSHOI-R1] 新概念报数 题解
    目录DescriptionSolutionCodeDescription在此题中,对于一个数\(x\),若\(\texttt{popcount}(x)\geq3\)(即\(x\)在二进制下\(\texttt{1}\)的个数大于等于三时),那它是非法的,否则其为合法的。给定\(T\)个数,如果当前的数\(x\)是非法的,则输出No,Commander,否则输出第一个大于......
  • ssr1
      从今天开始,将会和一起进步学习爬虫的小伙伴一块学习,讨论一下崔庆才的练习网站,分享一下自己在解决反爬网站的一些思路...  开始崔庆才的爬虫练习网站练习,后面会持续更新一系列关于该练习网站的每个练习案例的博客,用来练习和复习自己在细节知识点上掌握的不足。那么今天先看......
  • 树论
    1.重链剖分1.1.简介重链剖分将树分割成若干链维护信息,将树的结构转换为线性结构,然后可用其他数据结构维护。定义以下概念:重子节点轻子节点重边轻边重链某节点的子节点中子树大小最大的那个某节点的子节点中的非重子节点由某节点到其重子节点的连边由某节点到......
  • 2023-07-07:给出两个字符串 str1 和 str2。 返回同时以 str1 和 str2 作为子序列的最短
    2023-07-07:给出两个字符串str1和str2。返回同时以str1和str2作为子序列的最短字符串。如果答案不止一个,则可以返回满足条件的任意一个答案。输入:str1="abac",str2="cab"。输出:"cabac"。答案2023-07-07:大体步骤如下:1.初始化字符串str1和str2分别为"abac"......
  • 2023-07-07:给出两个字符串 str1 和 str2。 返回同时以 str1 和 str2 作为子序列的最短
    2023-07-07:给出两个字符串str1和str2。返回同时以str1和str2作为子序列的最短字符串。如果答案不止一个,则可以返回满足条件的任意一个答案。输入:str1="abac",str2="cab"。输出:"cabac"。答案2023-07-07:大体步骤如下:1.初始化字符串str1和str2分别为"abac"和"cab"......