【jzoi4587】Snow的追寻

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/lvzelong2014/article/details/83627258

【jzoi4587】Snow的追寻

并未注册成功,然而搞到了题目

题目大意

给定一颗树,求去掉两个子树的树直径
多组询问。

分析

线段树维护树的直径。
树的直径有一个性质。树中两个子树的最远点对一定再两个子树内部的直径上。
一共四个点。用线段树维护子树的直径,合并的时候 C 4 2 C_4^2 枚举一下。
L c a Lca r m q rmq ,不然复杂度会挂。

代码

#include<bits/stdc++.h>
const int N = 2e5 + 10;
int ri() {
	char c = getchar(); int x = 0, f = 1; for(;c < '0' || c > '9'; c = getchar()) if(c == '-') f = -1;
	for(;c >= '0' && c <= '9'; c = getchar()) x = (x << 1) + (x << 3) - '0' + c; return x * f;
}
int to[N], pr[N], nx[N], ps[N], in[N], out[N], z[2], A, tot, tp, n;
void add(int u, int v) {to[++tp] = v; nx[tp] = pr[u]; pr[u] = tp;}
void adds(int u, int v) {add(u, v); add(v, u);}
struct Distance {
	int de[N], bin[21], Lg[N], ps[N], mn[N][21], tp;
	int Be(int x, int y) {return de[x] < de[y] ? x : y;}
	void pre() {
		bin[0] = 1; for(int i = 1;i <= 20; ++i) bin[i] = bin[i - 1] << 1;
		Lg[0] = -1; for(int i = 1;i <= tp; ++i) Lg[i] = Lg[i >> 1] + 1;
		for(int j = 1; j <= 20; ++j)
			for(int i = 1;i <= tp - bin[j] + 1; ++i) 
				mn[i][j] = Be(mn[i][j - 1], mn[i + bin[j - 1]][j - 1]);
	}
	int Lca(int x, int y) {
		x = ps[x]; y = ps[y]; 
		if(x > y) std::swap(x, y);
		int t = Lg[y - x + 1];
		return Be(mn[x][t], mn[y - bin[t] + 1][t]);
	}
	int Get(int x, int y) {return de[x] + de[y] - (de[Lca(x, y)] << 1);}
}dis;
void Up(int x, int y, int *z) {
	if(!x || !y) return ;
	int d = dis.Get(x, y); if(d <= A) return ;
	A = d; z[0] = x; z[1] = y;
}
void Merge(int *x, int *y, int *z) {
	A = -1; int r[2];
	for(int i = 0;i < 2; ++i) for(int j = 0;j < 2; ++j)
		Up(x[i], y[j], r);
	Up(x[0], x[1], r); Up(y[0], y[1], r);
	z[0] = r[0]; z[1] = r[1];
}
struct Node {
	Node *ls, *rs; int v[2];
	void Build(int L, int R) {
		if(L == R) return void(v[0] = v[1] = ps[L]);
		int m = L + R >> 1;
		(ls = new Node)->Build(L, m);
		(rs = new Node)->Build(m + 1, R);
		Merge(ls->v, rs->v, v);
	}
	void Query(int L, int R, int st, int ed) {
		if(L == st && ed == R) return Merge(v, z, z);
		int m = L + R >> 1;
		if(st <= m) ls->Query(L, m, st, std::min(ed, m));
		if(ed > m) rs->Query(m + 1, R, std::max(m + 1, st), ed);
	}
}rt;
void Dfs(int u, int fa) {
	in[u] = ++tot; ps[tot] = u; dis.de[u] = dis.de[fa] + 1;
	dis.mn[++dis.tp][0] = u; dis.ps[u] = dis.tp;
	for(int i = pr[u]; i; i = nx[i])
		if(to[i] != fa) 
			Dfs(to[i], u), dis.mn[++dis.tp][0] = u;
	out[u] = tot;
}
void Que(int st, int ed) {
	if(st > ed) return ;
	rt.Query(1, n, st, ed);
}
int main() {
	freopen("snow.in","r",stdin);
	freopen("snow.out","w",stdout);
	n = ri(); int q = ri();
	for(int i = 1;i < n; ++i) adds(ri(), ri());
	tp = 0; Dfs(1, 0); dis.pre(); rt.Build(1, n);
	for(;q--;) {
		int x = ri(), y = ri(); z[0] = z[1] = 0;
		if(in[x] > in[y]) std::swap(x, y);
		Que(1, in[x] - 1);
		Que(out[x] + 1, in[y] - 1);
		Que(std::max(out[y], out[x]) + 1, n);
		printf("%d\n", dis.Get(z[0], z[1]));
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/lvzelong2014/article/details/83627258