zoukankan      html  css  js  c++  java
  • loj 3014「JOI 2019 Final」独特的城市

    loj

    我本来是直接口胡了一个意思一样的做法的,但是因为觉得有点假+实现要用并查集(?)就卡了好一会儿...

    对于一个点(x)来说,独特的点一定在它的最长链上,如果有独特的点不在最长链上,那么最长链上一定有和他到(x)距离相同的点,矛盾

    然后对于一个点,最长链端点一定可以是直径的两端点之一,所以如果我们分别以树的直径的两端点为根进行dfs,那么一个点在其中一次dfs中,独特的点都会在到根的路径上,所以我们用栈维护到根的点,然后不同颜色数开桶来维护,每次压栈或弹栈时改变桶内元素个数,然后根据某个桶元素变化维护当前答案

    然后在点(x)到根的路径上,其他挂出去的多余的链会往上覆盖掉一些点(也就是覆盖掉到(x)距离为某个值的点,它们不是独特的),导致这些点不能贡献答案.所以在dfs进别的子树时要用这些没用到的链来删掉一些点.具体来讲,dfs某个点时把父亲压入栈;在之前先预处理一个点子树内最长链长度以及次长链长度(最长链次长链要来自不同子树),然后先把到(x)距离(le)次长链长度的栈里的点弹掉,递归处理最长链所在子树,再把到(x)距离(le)最长链长度的栈里的点弹掉,这个时候维护的颜色种数就是当前这个点的答案,可以直接更新答案,之后递归其他子树处理.每个点答案为两个直径端点算出的值的max

    #include<bits/stdc++.h>
    #define LL long long
    #define uLL unsigned long long
    #define db double
    
    using namespace std;
    const int N=2e5+10;
    int rd()
    {
    	int x=0,w=1;char ch=0;
    	while(ch<'0'||ch>'9'){if(ch=='-') w=-1;ch=getchar();}
    	while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}
    	return x*w;
    }
    int to[N<<1],nt[N<<1],hd[N],tot=1;
    void add(int x,int y)
    {
    	++tot,to[tot]=y,nt[tot]=hd[x],hd[x]=tot;
    	++tot,to[tot]=x,nt[tot]=hd[y],hd[y]=tot;
    }
    int n,m,an[N],a[N],mx,r1,r2;
    void dd(int x,int ffa,int de)
    {
    	if(mx<de) mx=de,r2=x;
    	for(int i=hd[x];i;i=nt[i])
    	{
    		int y=to[i];
    		if(y==ffa) continue;
    		dd(y,x,de+1);
    	}
    }
    int de[N],dp[N],dp2[N],hs[N],stk[N],tp,bk[N],na;
    void dfs1(int x,int ffa)
    {
    	hs[x]=dp[x]=dp2[x]=0;
    	if(ffa&&!nt[hd[x]]){dp[x]=de[x];return;}
    	for(int i=hd[x];i;i=nt[i])
    	{
    		int y=to[i];
    		if(y==ffa) continue;
    		de[y]=de[x]+1,dfs1(y,x);
    		if(dp[y]>=dp[x]) hs[x]=y,dp2[x]=dp[x],dp[x]=dp[y];
    		else if(dp[y]>=dp2[x]) dp2[x]=dp[y];
    	}
    }
    void dfs3(int x,int ffa)
    {
    	if(ffa) stk[++tp]=ffa,na+=!bk[a[ffa]],++bk[a[ffa]];
    	if(!hs[x]) an[x]=max(an[x],na);
    	else
    	{
    		while(tp&&de[x]-de[stk[tp]]<=dp2[x]-de[x])
    			--bk[a[stk[tp]]],na-=!bk[a[stk[tp]]],--tp;
    		dfs3(hs[x],x);
    		while(tp&&de[x]-de[stk[tp]]<=dp[x]-de[x])
    			--bk[a[stk[tp]]],na-=!bk[a[stk[tp]]],--tp;
    		an[x]=max(an[x],na);
    		for(int i=hd[x];i;i=nt[i])
    		{
    			int y=to[i];
    			if(y==ffa||y==hs[x]) continue;
    			dfs3(y,x);
    		}
    	}
    	if(ffa&&stk[tp]==ffa) --bk[a[ffa]],na-=!bk[a[ffa]],--tp;
    }
    void wk(int rt)
    {
    	de[rt]=0,dfs1(rt,0);
    	dfs3(rt,0);
    }
    
    int main()
    {
    	n=rd(),m=rd();
    	for(int i=1;i<n;++i) add(rd(),rd());
    	for(int i=1;i<=n;++i) a[i]=rd();
    	mx=-1,dd(1,0,0),r1=r2;
    	mx=-1,dd(r1,0,0);
    	wk(r1),wk(r2);
    	for(int i=1;i<=n;++i) printf("%d
    ",an[i]);
    	return 0;
    }
    
  • 相关阅读:
    ArrayList用法
    MessageBox
    将文本文件导入Sql数据库
    在桌面和菜单中添加快捷方式
    泡沫排序
    Making use of localized variables in javascript.
    Remove double empty lines in Visual Studio 2012
    Using Operations Manager Connectors
    Clear SharePoint Designer cache
    Programmatically set navigation settings in SharePoint 2013
  • 原文地址:https://www.cnblogs.com/smyjr/p/11657526.html
Copyright © 2011-2022 走看看