ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

[JOISC2020] 首都

2022-07-15 21:06:43  阅读:168  来源: 互联网

标签:sz head 颜色 smx int void JOISC2020 首都


传送门

题意(建议看原题面)

\(n\)个点,\(k\)种颜色,每个点有一个颜色\(c_i\)。一次操作可以合并两种颜色。问最少多少次操作可以使存在一种颜色,把该颜色的点提取出来是联通的,换句话说该颜色的点两两之间(路径)不经过其它颜色。

思路

  • 先口胡一下我不太想写的倍增优化建图+Tarjan,贺了firm的代码进行学习。
    我想起来我之前做过一道倍增优化建图+网络流的
    连边的思路我考场上也想到了的,相同颜色\(i\)的两个节点路径上经过另一个颜色\(j\)的节点,就将\(i\)向\(j\)连边,相当于,颜色\(i\)需要把颜色\(j\)合并进来。
    如果\(j->u\),\(i->u\)发现这是传递性的,因此考虑缩点,显然答案出度为0的点sz-1的最小值。
    类似虚树的感觉,枚举颜色,提取出该颜色的点。按dfn排序,可以称按dfn排序后相邻的点在树上是相邻的(lca)最深
    排序后相邻的求lca,倍增优化建图(两端往lca上跳)。
    最后再跑Tarjan即可。

  • 还有之前老板讲过的点分治做法,比较好写。
    把分治中心的颜色当做首都,找它子树里面同样颜色的节点往上到中心的路径上出现的新颜色,加入队列。
    每次取出队首颜色,发现如果该颜色有节点出现在该子树外,直接结束。
    因为子树里到子树外的那个点的lca做分治中心不会更差(因为存在在路径中,当前分治中心一定连向它)。

  • code:

点击查看代码
#include<bits/stdc++.h>
using namespace std;
const int N=1e6+5;
int n,k,nxt[N],to[N],head[N],ecnt,c[N];
int sz[N],rt,smx[N],ans;
vector<int> V[N];
bool mark[N],vis[N],col[N];
void add_edge(int u,int v) {nxt[++ecnt]=head[u];to[ecnt]=v;head[u]=ecnt;}

void gt_sz(int u,int fa) {
	sz[u]=1;
	for(int i=head[u];i;i=nxt[i]) {
		int v=to[i];if(v==fa||mark[v])continue;
		gt_sz(v,u);
		sz[u]+=sz[v];
	}
}

void gt_rt(int u,int fa,int tot) {
	smx[u]=0;
	for(int i=head[u];i;i=nxt[i]) {
		int v=to[i];if(v==fa||mark[v])continue;
		gt_rt(v,u,tot);
		smx[u]=max(smx[u],sz[v]);
	}
	smx[u]=max(smx[u],tot-sz[u]);
	if(smx[u]<smx[rt])rt=u;
}
int tp,st[N],st2[N],tp2,f[N];
void dfs(int u,int fa) {
	vis[u]=1;st[++tp]=u;f[u]=fa;
	for(int i=head[u];i;i=nxt[i]) {
		int v=to[i];if(v==fa||mark[v])continue;
		dfs(v,u);
	}
}
queue<int> Q;	//the color we need

void Clear() {
	while(!Q.empty())Q.pop();
	while(tp) {vis[st[tp--]]=0;}
	while(tp2) {col[st2[tp2--]]=0;}
}
void solve(int u) {
	dfs(u,0);
	Q.push(c[u]);col[c[u]]=1;st2[++tp2]=c[u];
	bool flag=1;
	int res=0;
	while(flag&&!Q.empty()) {
		int cc=Q.front();Q.pop();
		res++;
		for(int i=0;i<V[cc].size();i++) {
			int x=V[cc][i],cf=c[f[x]];
			if(!vis[x]) {Clear();return;}
			if(!cf)continue;
			if(!col[cf]) {
				col[cf]=1;st2[++tp2]=cf;
				Q.push(cf);
			}
		}
	}
	ans=min(ans,res-1);
	Clear();
}

void Divide(int u,int tot) {
	rt=0;gt_rt(u,0,tot);
	mark[u=rt]=1;gt_sz(u,0);
	solve(u);
	for(int i=head[u];i;i=nxt[i]) {
		int v=to[i];if(mark[v])continue;
		Divide(v,sz[v]);
	}
}

int main() {
	smx[0]=1e9;
	scanf("%d%d",&n,&k);
	for(int i=1;i<n;i++) {int u,v;scanf("%d%d",&u,&v);add_edge(u,v),add_edge(v,u);}
	for(int i=1;i<=n;i++) {scanf("%d",&c[i]);V[c[i]].push_back(i);}
	ans=k-1;
	gt_sz(1,0);Divide(1,n);
	printf("%d",ans);
	return 0;
}

标签:sz,head,颜色,smx,int,void,JOISC2020,首都
来源: https://www.cnblogs.com/bestime/p/16482760.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有