1. 程式人生 > >Big Problems for Organizers CodeForces - 418D (貪心,直徑)

Big Problems for Organizers CodeForces - 418D (貪心,直徑)

ace inf fine def ios 端點 pop 討論 cpp

大意: 給定n結點樹, m個詢問, 每次給出兩個旅館的位置, 求樹上所有結點到最近旅館距離的最大值

先考慮一些簡單情形.

若旅館只有一個的話, 顯然到旅館最遠的點是直徑端點之一

若樹為鏈的話, 顯然是直徑端點或兩旅館的中點

這樣的話思路就來了, 也就是說最遠點要麽是直徑端點, 要麽是到兩旅館距離差不超過1的點

實際求的時候並不需要求出具體在那個點取得最大, 只需簡單分類討論一下, 用RMQ預處理一下, O(1)回答詢問

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <queue>
#define REP(i,a,n) for(int i=a;i<=n;++i)
#define pb push_back
using namespace std;

const int N = 1e5+10, INF = 0x3f3f3f3f;
int n, m, r1, r2, mx;
vector<int> g[N];
int vis[N], fa[N], s[N], dep[N], no[N];
int Log[N], w[N], f[2][20][N];

int bfs(int x) {
	memset(vis, 0, sizeof vis);
	queue<int> q;
	fa[x] = 0, vis[x] = 1, q.push(x);
	while (!q.empty()) {
		x = q.front();q.pop();
		for (int y:g[x]) if (!vis[y]) {
			vis[y] = 1, fa[y]=x, q.push(y);
		}
	}
	return x;
}

void dfs(int x, int fa, int d, int rt) {
	dep[x]=d, no[x]=rt, w[rt] = max(w[rt], d);
	for (int y:g[x]) if (!vis[y]&&y!=fa) {
		dfs(y,x,d+1,rt);
	}
}

int RMQ(int l, int r, int p) {
	if (l>r) return -INF;
	int t = Log[r-l+1];
	return max(f[p][t][l],f[p][t][r-(1<<t)+1]);
}

int main() {
	scanf("%d", &n);
	REP(i,2,n) {
		int u, v;
		scanf("%d%d", &u, &v);
		g[u].pb(v),g[v].pb(u);
	}
	r1 = bfs(1), r2 = bfs(r1);
	memset(vis, 0, sizeof vis);
	for (int i=r2; i; i=fa[i]) { 
		vis[i]=1, s[++*s]=i, no[i]=*s;
	}
	REP(i,1,*s) dfs(s[i],0,0,i);
	Log[0] = -1;
	REP(i,1,n) { 
		f[0][0][i]=w[i]+i,f[1][0][i]=w[i]-i;
		Log[i] = Log[i>>1]+1;
	}
	REP(j,1,19) for (int i=1;i+(1<<j-1)<=n; ++i) {
		f[0][j][i] = max(f[0][j-1][i],f[0][i+(1<<j-1)][j-1]);
		f[1][j][i] = max(f[1][j-1][i],f[1][i+(1<<j-1)][j-1]);
	}
	scanf("%d", &m);
	REP(i,1,m) {
		int x, y, ans;
		scanf("%d%d", &x, &y);
		int l=no[x], r=no[y];
		if (l>r) swap(l,r),swap(x,y);
		if (l==r) {
			printf("%d\n", max(l-1,*s-l)+min(dep[x],dep[y]));
			continue;
		}
		int mid = l+r-dep[x]+dep[y];
		if (mid<=2*l) ans = max(r-1,*s-r)+dep[y];
		else if (mid>=2*r) ans = max(l-1,*s-l)+dep[x];
		else {
			mid /= 2;
			int L=max(l-1,RMQ(l+1,mid,0)-l)+dep[x];
			int R=max(*s-r,RMQ(mid+1,r-1,1)+r)+dep[y];
			ans = max(L,R);
		}
		printf("%d\n", ans);
	}
}

Big Problems for Organizers CodeForces - 418D (貪心,直徑)