CF519E A and B and Lecture Rooms (思维+lca)

题意

每次询问点x,y,要你求其中离它距离一样的点。

做法

非常简单我们分类讨论即可
如果 两点深度相同 是同一个点 那么就是n
不是同一个点就是 n-top [a] -top [b]
深度不同 如果距离为奇数显然无解
深度为 偶数 我们找到中点 那么 就是
中点为根的子树 减去 中点深度-1 的那个子树(在深度大的那条链上
代码也是非常好写

代码细节如下

#include <bits/stdc++.h>
using namespace  std;
//#define  int long long
typedef long long ll;
typedef pair<int, int> pii;
typedef vector<int> vi;
#define fi first
#define se second
#define pb  push_back
#define inf 1<<62
#define endl "\n"
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
#define de_bug(x) cerr << #x << "=" << x << endl
#define all(a) a.begin(),a.end()
#define IOS   std::ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define  fer(i,a,b)  for(int i=a;i<=b;i++)
#define  der(i,a,b)  for(int i=a;i>=b;i--)
const int mod = 1e9 + 7;
const int N = 1e6 + 10;
int n, m , k;

vi g[N];
int  d[N];
int  f[N][22];
int siz[N];
void dfs(int u, int fa) {
	d[u] = d[fa] + 1;
	f[u][0] = fa;
	siz[u] = 1;
	for(int i = 1; i <= 20; i++)
		f[u][i] = f[f[u][i - 1]][i - 1];
	for(auto v : g[u]) {
		if(v == fa)continue;
		dfs(v, u);
		siz[u] += siz[v];
	}
}
int lca(int a, int b) {
	if(d[a] < d[b]) swap(a, b);
	for(int i = 20; i >= 0; i--) {
		if(d[f[a][i]] >= d[b])
			a = f[a][i];
	}
	if(a == b)return a;
	for(int i = 20; i >= 0; i--) {
		if(f[a][i] != f[b][i])
			a = f[a][i],
			b = f[b][i];
	}
	return f[a][0];
}
inline int get_pos (int x, int s) {
	int now = x;
	if(s < 0)return now;
	for(int i = 20; i >= 0; i--) {
		if((s >> i) & 1)now = f[now][i];
	}
	return now;
}
int lca2(int a, int b) {
	if(d[a] < d[b]) swap(a, b);
	for(int i = 20; i >= 0; i--) {
		if(d[f[a][i]] >= d[b])
			a = f[a][i];
	}
	if(a == b)return a;
	for(int i = 20; i >= 0; i--) {
		if(f[a][i] != f[b][i])
			a = f[a][i],
			b = f[b][i];
	}
	return n - siz[a] - siz[b];
}
void solve() {
	cin >> n;
	fer(i, 1, n - 1) {
		int a, b;
		cin >> a >> b;
		g[a].push_back(b);
		g[b].push_back(a);
	}
	cin >> m;
	dfs(1, 0);
	fer(i, 1, m) {
		int a, b;
		cin >> a >> b;
		int LCA = lca(a, b);
		if(d[a] == d[b]) {
			if(a == b)cout << n << endl;
			else {
				cout << lca2(a, b) << endl;
			}
		} else {
			int dis = (d[a] + d[b] - 2 * d[LCA]);
			if(dis % 2 == 1) {
				cout << 0 << endl;
				continue;
			}
			if(d[a] < d[b])swap(a, b);
			int pos = get_pos(a, dis / 2);
			int tmp = get_pos(a, d[a] - d[pos] - 1);
			cout << siz[pos] - siz[tmp] << endl;
		}
	}
}
int main() {
	IOS;
	int _ = 1;
	//cin>>_;
	while( _-- )
		solve();
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值