ZOJ - 4048(2018 青岛网络赛B) LCA + 二分思想

版权声明:欢迎随便转载。 https://blog.csdn.net/a1214034447/article/details/82749276

题目链接:点击这里

解题思路:

首先预处理出原来树中节点u的C(u)值,那么在给出的ki个节点后,将他们根据原C()大小从大到小排序.

那么假设最小情况下最大值不会超过第i个C()值,那么意思就是前i个节点的C()值要做出改变才行,怎么让他们都改变呢?

将红点设在前i个点的最近公共祖先上,就可以将他们都改变,且尽量最小.

对于前i个点C()的变化后最大值也可以递推求出.

#include<bits/stdc++.h>
#define inf 0x3f3f3f3f
#define fi first
#define se second
using namespace std;
typedef long long ll;
const int mx = 1e5 + 10;
int t,n,m,R[mx],cnt[mx],fa[mx][20];
int deep[mx];
ll D[mx],dis[mx];
bool red[mx];
vector <pair<int,int>> vec[mx];
void dfs(int x,int f)
{
	if(red[x]) R[x] = x;
	else R[x] = R[f];
	dis[x] = (D[x]-D[R[x]]);
	for(auto v:vec[x])
	{
		if(v.fi==f) continue;
		D[v.fi] = D[x] + v.se;
		deep[v.fi] = deep[x] + 1;
		fa[v.fi][0] = x;
		dfs(v.fi,x);
	}
}
bool cmp(ll a,ll b)
{
	return dis[a] > dis[b];
}
void RMQ(int N){
	for(int j=1;(1<<j)<=N;j++)
	for(int i=1;i<=N;i++)
	fa[i][j]=fa[fa[i][j-1]][j-1];
}
int LCA(int u,int v){
	if(deep[u]<deep[v])  swap(u,v);
	int de=log(deep[u])/log(2.0);
	for(int i=de;i>=0;i--)
	if(deep[u]-(1<<i)>=deep[v])
	u=fa[u][i];
	if(v==u)  return u;
	for(int i=de;i>=0;i--){
		if(fa[u][i]!=fa[v][i]){
			u=fa[u][i];
			v=fa[v][i];
		}
	}
	return fa[v][0];
}
int main()
{    
    int t,q;
    scanf("%d",&t);
    while(t--){
    	scanf("%d%d%d",&n,&m,&q);
    	int a,b,c;
    	for(int i=1;i<=n;i++) red[i] = 0,vec[i].clear();
    	for(int i=1;i<=m;i++){
    		scanf("%d",&a);
    		red[a] = 1;
		}
		dis[n+1] = D[1] = dis[1] = 0;
		deep[1] = 1;
		for(int i=1;i<n;i++){
			scanf("%d%d%d",&a,&b,&c);
			vec[a].push_back(make_pair(b,c));
			vec[b].push_back(make_pair(a,c));
		}
		dfs(1,0);
		RMQ(n);
		int k;
		while(q--){
			scanf("%d",&k);
			ll ans = 0,maxx = 0,lon;
			for(int i=0;i<k;i++){
				scanf("%d",cnt+i);
			}
			cnt[k] = n+1;
			sort(cnt,cnt+k,cmp);
			ans = dis[cnt[0]];
			int far = cnt[0],mom,Mdep = deep[R[cnt[0]]];
			ans = min(ans,dis[cnt[1]]);
			for(int i=1;i<k;i++)
			{
				mom = LCA(far,cnt[i]);
				Mdep = max(Mdep,deep[R[cnt[i]]]);
				if(deep[mom]<deep[far]) maxx += D[far] - D[mom];
				if(Mdep>=deep[mom]) break;
				maxx = max(D[cnt[i]]-D[mom],maxx);
				far = mom;
				ans = min(ans,max(maxx,dis[cnt[i+1]]));
			}
			printf("%lld\n",ans);
		}
    }
    return 0; 
}

猜你喜欢

转载自blog.csdn.net/a1214034447/article/details/82749276
今日推荐