1. 程式人生 > 其它 >牛客多校8 J-Tree

牛客多校8 J-Tree

原題連結
樹上兩點之間的路徑是唯一的,我們發現,當有人脫離了兩者之間的路徑時,他所走的步數不會被對方所幹預(雙方已經毫無關係了),故可以對抗搜尋,當有一方離開兩點路徑之時,直接統計答案。
詳情見程式碼:

/*
牛客多校8-J
對抗搜尋,剪枝,rmq表預處理。
思路:
dfs1預處理出s到t 的唯一路徑
dfs2預處理出s到t唯一路徑上每一點下懸掛的最長路徑,用path[i]儲存。
path1[i]表示s選擇在i點離開唯一路徑時,所獲得的最多操作步數 
path2[i]表示t選擇在i點離開唯一路徑時,所獲得的最多操作步數 
F[][], G[][] 為path1[], path2[]兩陣列rmq詢問前的預處理陣列。
max1(l, r) 表示path1[l].....path1[r]的最大值 
max2(l, r) 表示path2[l].....path2[r]的最大值
對抗搜尋,分mode 0,表示s方要最優的決策,  mode 1, 表示t方要最優的決策
當狀態遇到(i, j, 0)時,有2種選擇:
1、s方在i點離開2者之間的路徑, 則答案為path1[i]
在這之後,t方的答案就是max2(i + 1, j) //在(i + 1, j)區間中進行rmq詢問。
2、進行狀態(i + 1, j , 1). 
同理狀態(i, j, 1); 
*/
#include <bits/stdc++.h>
using namespace std;
#define N 500005
int n, s, t, to[N << 1], nxt[N << 1], head[N], path[N << 1], inp[N], vis[N], cnt, m;
int path1[N << 1], path2[N << 1]; 
int F[20][N], G[20][N];
int max1(int l,int r) {
    int x = log2(r - l + 1);
    return max(F[x][l], F[x][r - (1 << x) + 1]);
} 
int max2(int l,int r) {
    int x = log2(r - l + 1);
    return max(G[x][l], G[x][r - (1 << x) + 1]);
}
void ae(int x,int y) {
    to[++cnt] = y, nxt[cnt] = head[x], head[x] = cnt;
}
int dfs1(int u, int t, int dep) {
	vis[u]=1;
	if(u == t) {
		path[dep] = u;
		inp[u] = 1;
		return dep;
	}
	for(int i = head[u]; i; i = nxt[i]) {
        int y = to[i];
        if(!vis[y]) {
        	int tmp = dfs1(y, t, dep + 1);
        	if(tmp) {
        		path[dep] = u;
        		inp[u] = 1;
        		return tmp;
			}
        }
    }
    return 0; 
}
int dfs2(int u, int dep) {
	vis[u] = 1; int tmp = dep;
	for(int i = head[u]; i; i = nxt[i]) {
        int y = to[i];
        if(!vis[y] && !inp[y]) {
        	tmp = max(tmp, dfs2(y, dep + 1));
        }
    }
    return tmp;
}
void init() {
	for(int i = 1; i <= m; i++) {
		F[0][i] = path1[i], G[0][i] = path2[i];	
	}
    for(int i = 1; i <= 19; i++) {
    	for(int j = 1; j + (1 << (i - 1)) <= m; j++) {
    		F[i][j] = max(F[i - 1][j], F[i - 1][j + (1 << (i - 1))]);
		}
	}
    for(int i = 1; i <= 19; i++) {
    	for(int j = 1; j + (1 << (i - 1)) <= m; j++) {
        	G[i][j] = max(G[i-1][j], G[i - 1][j + (1 << (i - 1))]);
		}
	}
}

int dfs3(int i, int j, int mode) {
	if(mode == 0) {
		int score = path1[i] - max2(i + 1, j);
		if(i + 1 < j) return max(score, -dfs3(i + 1, j, 1));
		else return score;
	}
	if(mode == 1) {
		int score = path2[j] - max1(i, j - 1);
		if(i + 1 < j) return max(score, -dfs3(i, j - 1, 0));
		else return score;
	}
}

int main() {
    scanf("%d %d %d", &n, &s, &t);
    for(int i = 1; i < n; i++) {
        int ui, vi;
        scanf("%d %d", &ui, &vi);
        ae(ui, vi); ae(vi, ui);
    }
    memset(vis,0,sizeof(vis));
    m = dfs1(s, t, 1);
    memset(vis, 0, sizeof(vis));
    for(int i = 1;i <= m; i++) {
    	path[i] = dfs2(path[i], 0);
	}
	for (int i = 1; i <= m; i++) {
		path1[i] = path[i] + i - 1;
		path2[i] = path[i] + m - i;
	}
	init();
	printf("%d\n", dfs3(1, m, 0));
    return 0;
}