Borrow Classroom (LCA 倍增 )

題目連接    

題意:
         一個N 個節點的樹 N-1條邊, 1號節點是根節點,Q次詢問,每次詢問3個整數 
         A B C 3個人(3個整數代表3個人所處的位置),
        要求A 在文件交到根節點前進行攔截 
        如果A C同時到1則算失敗 
    數據範圍
        3s 
        最多5組樣例 
        n q <= 1e5
        時間分析可以用靜態的Tarjan來求LCA 和倍增 求LCA
        離線算法 用Tarjan可能會快一點都試試吧 
    思路: 
         1) A到1的距離 要小於( B到 C的距離 + C到 1的距離) 
        2) 如果 A到1的距離 等於( B到 C的距離 + C到 1的距離)要判斷是否在中途相遇 即LCA(a,c) != 1 
        3)A到1 的距離是 A的樹深,
        4)B到C的距離可以用LCA(a, b)來求,dis[a] + dis[b] - 2 * dis[LCA(a,b)]
        5) C到1的距離是 C的樹深 

LCA 倍增AC:

#include<bits/stdc++.h>
using namespace std;
const int MAXN = 1e5 + 5;
int head[MAXN], cnt;
int depth[MAXN], fa[MAXN][30];
struct Edge{
	int to, dis, next;
}edge[MAXN << 1];
int n, q;
void add_edge(int u, int v, int dis) {
	edge[++cnt].to = v;
	edge[cnt].dis = dis;
	edge[cnt].next = head[u];
	head[u] = cnt; 
}
void init () {
	cnt = 1;
	memset(head, 0, sizeof(head)); 
	memset(depth, 0, sizeof(depth)); 
	memset(fa, 0, sizeof(fa)); 
}
void DFS(int now, int pre) {
	depth[now] = depth[pre] + 1;
	fa[now][0] = pre;
	for(int i = 1; (1 << i) <= depth[now]; ++i) {
		fa[now][i] = fa[fa[now][i - 1]][i - 1];
	}
	for (int i = head[now]; i; i = edge[i].next) {
		if(edge[i].to != pre) 
			DFS(edge[i].to, now);
	}
}
int LCA(int a, int b) {
	if(depth[a] < depth[b]) swap(a, b);
	int dep = depth[a] - depth[b];
	for (int i = 0; (1 << i) <= dep; ++i) {
		if((1 << i) & dep) {
			a = fa[a][i];
		}
	}
	if(a == b) return a;
	for (int i = log2(depth[a]); i >= 0; --i) {
		//如果父親不同就向上跳, 如果父親相同就減小距離再比較,直到不相同在跳。 
		if (fa[a][i] != fa[b][i]) {
			a = fa[a][i];
			b = fa[b][i];	
		}
	}
	return fa[a][0];
}
int distant(int a, int b) {
	int temp = LCA(a, b);
 	return depth[a] + depth[b] - 2 * depth[temp];
}
int main() {	
	int T;
	scanf("%d", &T);
	while(T--) {
		init(); 
		cin >> n >> q;
		int x, y;
		for(int i = 1; i < n; ++i) {
			scanf("%d%d", &x, &y);
			add_edge(x, y, 0);
			add_edge(y, x, 0);
		}
		int A, B, C;
		DFS(1, 1);
		for(int i = 1; i <= q; ++i) {
			scanf("%d%d%d", &A, &B, &C);
			int dis_BC = distant(B, C);
			int dis_A1 = depth[A]; 
			int dis_C1 = depth[C];
			bool flag = 0;
			if(dis_A1 < dis_BC + dis_C1) flag = 1;
			else if ((dis_A1 == dis_BC + dis_C1) && LCA(A, C) != 1) flag = 1;
			
			if(flag) printf("YES\n");
			else printf("NO\n");
		}
	}
	return 0;
}

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章