#213. 旅行

猫大告诉我们,对于每坨c一样的点,有贡献的只有距离最远的两个。证明略。

那么如何求呢?只要每次取三个点,lca搞一发,保留两个就好了。

对于c不同的点怎么办呢?也搞成两个。做完了。

但是要注意计算答案时要将同颜色的两个有效点同时参与答案的计算,然后在将这两个点与最佳点比较。

我讲得不好,具体看代码。感觉这次的代码写的蛮顺眼的。

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdlib>
using namespace std;
#define rep(i,j,k) for(i=j;i<=k;++i)
#define per(i,j,k) for(i=j;i>=k;--i)
#define ll long long
#define db double
#define mkp(x,y) make_pair(x,y)
#define pii pair<int,int>
#define X first
#define Y second
const int N=100005;
int he[N],to[N<<1],ne[N<<1],tot;
int n,c[N],dep[N],dad[N],son[N],sz[N],pre[N];
int m,gs[N],cs1[N],cs2[N],ans;
int lca(int x,int y){
	int fx=dad[x],fy=dad[y];
	while(fx!=fy)
		if(dep[fx]>dep[fy])fx=dad[x=pre[fx]];
		else fy=dad[y=pre[fy]];
	return dep[x]<dep[y]?x:y;
}
void DFS1(int x,int e){
	int y,i;
	dep[x]=dep[to[e]]+1;sz[x]=1;
	for(i=he[x];i;i=ne[i])if(i!=e){
		pre[y=to[i]]=x;DFS1(y,i^1);
		if(sz[y]>sz[son[x]])son[x]=y;
		sz[x]+=sz[y];
	}
}
void DFS2(int x,int e){
	int y=to[e],i;
	dad[x]=son[y]==x?dad[y]:x;
	for(i=he[x];i;i=ne[i])if(i!=e)
		DFS2(to[i],i^1);
}
int cal(int x,int y){
	return dep[x]+dep[y]-(dep[lca(x,y)]<<1)+1;
}
void get(int &x,int &y,int z){
	int m1=cal(x,y),m2=cal(x,z),m3=cal(y,z),mm;
	mm=max(m1,max(m2,m3));
	if(mm==m2)y=z;
	else if(mm==m3)x=z;
/*	if(c[x]==c[y]){
		if(c[y]==c[z]){
			mm=max(m1,max(m2,m3));
			if(mm==m2)y=z;
			else if(mm==m3)x=z;
		}
		else{
			if(m2>m3)y=z;
			else x=z;
		}
		return;
	}
	if(c[y]==c[z]){
		if(m2>m1)y=z;
	}
	else if(c[x]==c[z]){
		if(m3>m1)x=z;
	}
	else{
		mm=max(m1,max(m2,m3));
		if(mm==m2)y=z;
		else if(mm==m3)x=z;
	}*/
}
void ins(int x,int i){
	if(!gs[x])gs[x]=1,cs1[x]=i;
	else if(gs[x]==1)gs[x]=2,cs2[x]=i;
	else get(cs1[x],cs2[x],i);
}
void add(int x,int y){
	to[++tot]=y;ne[tot]=he[x];he[x]=tot;
}
int main(){
	int i,x,y,Q,k;
	scanf("%d%d%d",&n,&m,&Q);tot=1;
	rep(i,1,n)scanf("%d",&c[i]);
	rep(i,2,n){
		scanf("%d%d",&x,&y);
		add(x,y),add(y,x);
	}
	DFS1(1,0);DFS2(1,0);
	rep(i,1,n)ins(c[i],i);
	while(Q--){
		scanf("%d",&k);gs[0]=cs1[0]=cs2[0]=ans=0;
		while(k--){
			scanf("%d",&x);
			if(gs[x]){
				if(gs[0])ans=max(ans,cal(cs1[0],cs1[x]));
				if(gs[0]>1)ans=max(ans,cal(cs2[0],cs1[x]));
			}
			if(gs[x]>1){
				if(gs[0])ans=max(ans,cal(cs1[0],cs2[x]));
				if(gs[0]>1)ans=max(ans,cal(cs2[0],cs2[x]));
			}
			if(gs[x])ins(0,cs1[x]);
			if(gs[x]>1)ins(0,cs2[x]);
		}
		if(!ans)ans=-1;printf("%d\n",ans);
	}
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值