专栏文章

题解:AT_joi2019ho_e 珍しい都市 (Unique Cities)

AT_joi2019ho_e题解参与者 2已保存评论 1

文章操作

快速查看文章及其快照的属性,并进行相关操作。

当前评论
1 条
当前快照
1 份
快照标识符
@minn457a
此快照首次捕获于
2025/12/02 05:07
3 个月前
此快照最后确认于
2025/12/02 05:07
3 个月前
查看原文
题意:一棵树,每个点有颜色,对于每个点为根,你需要知道其最长链上该深度的点唯一的点的颜色种类数。
题解:结论,每个点为根的最长链一定是以该树的直径两端点其一为端点的链,否则直径长度会变大。
22 种情况分讨一下,取最大值就做完了。
细节:
  1. 父节点入栈。
  2. 将栈中节点到这个点深度 \leq 这个点的次长链深度的弹出
  3. 遍历最长链儿子。
  4. 将栈中节点到这个点距离 \leq 这个点向下最长链的弹出。
  5. 计算这个点答案:桶里面的元素个数。
  6. 处理其他儿子。
  7. 回溯,如果该点有父亲,将父节点弹出。
说明,每次 dfs 到一个点是就是考虑以这个点为根,所以上述操作就好理解了。
Code:他明白 他明白 我给不起~!
CPP
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define pii pair<int,int>
#define fi first
#define se second

const int N=500010;

vector<int> f[N];

int dis[N],far,s,t1,mx[N],siz,shu[N],m[N],col[N],_,ans[N],g[N],n,x,y;

void get(int u,int f1){
	for(int v:f[u]){
		if(v==f1)continue;
		dis[v]=dis[u]+1;
		get(v,u);
	}
	mx[u]=max(mx[u],dis[u]);
	if(dis[far]<dis[u])far=u;
}

int dep[N],son[N][2],id,t[N];

void dfs(int u,int f1){
	dep[u]=dep[f1]+1;
	son[u][0]=son[u][1]=0;
	for(int v:f[u]){
		if(v==f1)continue;
		dfs(v,u);
		if(g[v]>g[son[u][0]]){
			son[u][1]=son[u][0];
			son[u][0]=v;
		}else if(g[v]>g[son[u][1]]){
			son[u][1]=v;
		}
	}
	g[u]=g[son[u][0]]+1;
}

stack<int> st;

void dfs1(int u,int f1){
	if(f1){
		st.push(f1);
		t[col[f1]]++;
		if(t[col[f1]]==1)id++;
	}
	if(son[u][0]){
		while(!st.empty()&&dep[st.top()]>=dep[u]-g[son[u][1]]){
			t[col[st.top()]]--;if(t[col[st.top()]]==0)id--;st.pop();
		}
		dfs1(son[u][0],u);
	}
	while(!st.empty()&&dep[st.top()]>=dep[u]-g[son[u][0]]){
		t[col[st.top()]]--;if(t[col[st.top()]]==0)id--;st.pop();
	}
	for(int v:f[u]){
		if(v==f1||v==son[u][0])continue;
		dfs1(v,u);
	}
	ans[u]=max(ans[u],id);
	if(!st.empty()&&st.top()==f1){
		t[col[st.top()]]--;if(t[col[st.top()]]==0)id--;st.pop();
	}
}

signed main(){
	ios::sync_with_stdio(0);
	cin.tie(0);cout.tie(0);
    cin>>n>>_;
	for(int i=1;i<n;i++){
		cin>>x>>y;
		f[x].push_back(y);
		f[y].push_back(x);
	}
	for(int i=1;i<=n;i++){
		cin>>col[i];
	}
    s=1;get(s,0);s=far;memset(dis,0,sizeof dis);far=0;get(s,0);t1=far;
//	siz=dis[t];
//    memset(mx,0,sizeof mx);get(s,0);memset(dis,0,sizeof dis);get(t,0);
//    for(int i=1;i<=n;i++){
//    	if(dis[i]==mx[i])shu[i]=t,m[i]=mx[i]-(siz-mx[i]);
//    	else shu[i]=s,m[i]=mx[i]-(siz-mx[i]);
//	}
	dfs(s,0);dfs1(s,0);memset(son,0,sizeof son);
	dfs(t1,0);dfs1(t1,0);
	for(int i=1;i<=n;i++)
	cout<<ans[i]<<"\n";
    return 0;
}

评论

1 条评论,欢迎与作者交流。

正在加载评论...