zoukankan      html  css  js  c++  java
  • 2021湖南多校对抗赛第二场 C

    题目链接:

    https://vjudge.net/contest/430000#problem/C

    Solution:

    题目保证有解,所以对于一组颜色相同的点,它们必定分布在一条树链上

    所以求每一个颜色对应的两个端点,就是求一条能够包含这个颜色所有点的树链

    我们不妨先dfs处理出每个点的深度,并对于每个颜色,记录出它深度最大和最小的点,分别记为(u_1)(u_2)

    显然最深的点一定可以作为这个颜色的一个端点

    考虑某个颜色对应的链,分为两种情况,若这种颜色其他点都是(u_1)的祖先(也就是以(u_1)为起始沿着每个点的父亲一路向上的一条链,每个点与(u_1)的LCA都是他本身),那么(u_2)就是另一个端点;反之,若我们找到一类点,它不是(u_1)的祖先(该点与(u_1)的LCA不是他本身),那么,这类点中最深的点就是另一个端点

    这一步我们可以用LCA来实现,这样一来,我们就处理出了每个颜色的两个端点了

    下一步我们考虑安排颜色间的先后顺序,也就是每个颜色的拓扑序

    由于一定有解,我们考虑,在某个颜色(C)对应的链上,若出现了另一个颜色(D)的点,显然,(D)一定在(C)后面(每个颜色只能画一次,(D)又出现在了(C)对应的链上,那么(D)肯定是把这个点之前的颜色(C)给覆盖了),我们在拓扑图上把(C)(D)连一条有向边即可

    枚举每个颜色(C),处理其对应的链,设(C)的两个端点为(c_1),(c_2),我们分别从(c_1,c_2)出发向上走到他们的LCA,遇到不是(C)的颜色在拓扑图上连边即可

    这样对于每个颜色的连边是(O(n))的,我们可以用倍增优化

    也就是当我们在(C)对应的链上遇到了另一种颜色(D),我们直接倍增(log(n))走完颜色(D)即可(若是颜色(C)就不要倍增跳了,因为可能会跳过链上的一些颜色导致遗漏,所以在颜色为(C)的点上还是老老实实往上跳吧,复杂度也不会炸,因为每个点你仅会用(O(n))的方式处理一次,遇到不属于颜色(C)的点再跳)

    处理完所有颜色连好边后做个拓扑排序就行了

    #include<bits/stdc++.h>
    using namespace std;
    struct front_star{
    	int to,next;
    }e[200005];
    int n,m,cnt=0,tot=0;
    int col[100005],head[100005],f[100005][18],d[100005],tl[100005],hd[100005],tp[100005],deg[100005],ans[100005],p[100005];
    set<int>s[100005];
    vector<int>g[100005];
    void addedge(int u,int v)
    {
    	cnt++;
    	e[cnt].to=v;
    	e[cnt].next=head[u];
    	head[u]=cnt;
    }
    void get_deep(int u,int fa)
    {
    	f[u][0]=fa;
    	for(int i=1;i<=17;i++)
    		f[u][i]=f[f[u][i-1]][i-1];
    	d[u]=d[fa]+1;
    	if(tl[col[u]]==0)
    	   tl[col[u]]=u;
    	else
    	{
    		if(d[tl[col[u]]]<d[u])
    		   tl[col[u]]=u;
    	}
    	if(tp[col[u]]==0)
    	   tp[col[u]]=u;
    	else
    	{
    		if(d[tp[col[u]]]>d[u])
    		   tp[col[u]]=u;
    	}
    	for(int i=head[u];~i;i=e[i].next)
    	{
    	    if(e[i].to!=fa)
    	       get_deep(e[i].to,u);
        }
    }
    int get_lca(int x,int y)
    {
    	if(d[x]<d[y])
    	   swap(x,y);
    	for(int i=17;i>=0;i--)
    	{
    		if(d[x]-(1<<i)>=d[y])
    			x=f[x][i];
    	}
    	if(x==y)
    	   return x;
    	for(int i=17;i>=0;i--)
    	{
    		if(f[x][i]!=f[y][i])
    		{
    			x=f[x][i];
    			y=f[y][i];
    		}
    	}
    	return f[x][0];
    }
    void jump(int u,int r,int des)
    {
    	if(u==des)
    	   return;
    	if(col[u]==r)
    	{
    		if(col[f[u][0]]!=r)
    			s[col[f[u][0]]].insert(r);
    		if(d[f[u][0]]>=d[des])	
    		   jump(f[u][0],r,des);	
    	}
    	else
    	{
    		if(d[p[col[u]]]<d[des])
    		   return;
    		if(col[u]!=col[f[u][0]])
    	    {
    		    if(col[f[u][0]]!=r)
    			   s[col[f[u][0]]].insert(r);
    		    if(d[f[u][0]]>=d[des])	
    		       jump(f[u][0],r,des);	
    	    }
    		else
    		{
    			for(int i=17;i>=0;i--)
    			{
    				if(col[f[u][i]]==col[u])
    				{
    					if(d[f[u][i]]<d[des])
    					   return;
    					else
    					{
    						jump(f[u][i],r,des);
    						break;
    					}   	
    				}
    			}
    		}   
    	}   
    }
    void top_sort()
    {
    	queue<int>q;
    	while(!q.empty()) q.pop();
    	for(int i=1;i<=m;i++)
    	{
    		if(deg[i]==0)
    		   q.push(i);
    	}
    	while(!q.empty())
    	{
    		int t=q.front();
    		q.pop();
    		tot++;
    		ans[tot]=t;
    		int upp=g[t].size();
    		for(int i=0;i<upp;i++)
    		{
    			deg[g[t][i]]--;
    			if(deg[g[t][i]]==0)
    			   q.push(g[t][i]);
    		}
    	}
    }
    int main()
    {
    	memset(head,-1,sizeof(head));
    	memset(f,0,sizeof(f));
    	memset(tl,0,sizeof(tl));
    	memset(tp,0,sizeof(tp));
    	memset(hd,0,sizeof(hd));
    	memset(deg,0,sizeof(deg));
    	scanf("%d%d",&n,&m);
    	for(int i=1;i<=n;i++)
    	    scanf("%d",&col[i]);
    	for(int i=1;i<=m;i++)
    	{
    		s[i].clear();
    		g[i].clear();
    	}
    	for(int i=1;i<=n-1;i++)
    	{
    		int a,b;
    		scanf("%d%d",&a,&b);
    		addedge(a,b);
    		addedge(b,a);
    	}
    	d[0]=0;
    	get_deep(1,0);
    	for(int i=1;i<=n;i++)
    	{
    		int c=col[i];
    		if(i!=tl[c]&&tl[c]!=0)
    		{
    			if(get_lca(i,tl[c])!=i&&d[i]>d[hd[c]])
    			   hd[c]=i;
    		} 
    	}
    	for(int i=1;i<=m;i++)
    	{
    		if(hd[i]==0)
    		   hd[i]=tp[i];
    		p[i]=get_lca(hd[i],tl[i]);   
    	}
        for(int i=1;i<=m;i++)
        {
        	if(hd[i]!=0&&tl[i]!=0)
        	{
        		int lca=get_lca(tl[i],hd[i]);
        		jump(tl[i],i,lca);
        		jump(hd[i],i,lca);
    		}
    	}
    	for(int i=1;i<=m;i++)
    	{
    		for(set<int>::iterator it=s[i].begin() ;it!=s[i].end();it++)
    		{
    			int c=*it;
    			g[c].push_back(i);
    			deg[i]++;
    		}
    	}
    	for(int i=1;i<=m;i++)
    	{
    		if(tl[i]==0||hd[i]==0)
    		   printf("%d %d %d
    ",i,1,1);
    	}	
    	top_sort();
    	for(int i=1;i<=m;i++)
    	{
    		if(hd[ans[i]]!=0&&tl[ans[i]]!=0)
    	       printf("%d %d %d
    ",ans[i],tl[ans[i]],hd[ans[i]]);
        }
    	return 0;
    }
    
    小鳥の翼がついに大きくなって , 旅立ちの日だよ , 遠くへと広がる海の色暖かく , 夢の中で描いた絵のようなんだ , 切なくて時をまきもどしてみるかい ? No no no いまが最高! だってだって、いまが最高!
  • 相关阅读:
    Java的Object类
    java中String、StringBuffer、StringBuilder的区别
    Java正则表达式
    《java编程思想》P160-P180(第八章部分+第九章部分)
    《java编程思想》P140-P160(第七章复部+第八章部分)
    《java编程思想》P125-P140(第七章复用类部分)
    Servlet 工作原理解析
    大型高性能网站的十项规则
    Java 理论与实践: 并发在一定程度上使一切变得简单
    Java并发基础构建模块简介
  • 原文地址:https://www.cnblogs.com/nanjolno/p/14646400.html
Copyright © 2011-2022 走看看