【題解】codeforces741D Arpa’s letter-marked tree and Mehrdad’s Dokhtar-kosh paths

題目鏈接

題意:給定一棵有根樹,結點編號爲1~n,根結點爲結點1。每條邊上有一個字母,求各子樹內最長的滿足“路徑上的字母經過重排後可以構成迴文串”的簡單路徑。

分析:對結點u,用2進制數vec[u]表示結點u到根結點的路徑上各字母的數目的奇偶性。若第i個字母數目爲奇數則vec[u]的第i位爲1,否則爲0。子樹u內滿足要求的路徑可以分成兩類,一類經過結點u,一類不經過結點u。由於不經過結點u的路徑的長度最大值可以遞歸求得,因此這裏僅需考慮經過結點u的路徑。用cnt[S]表示子樹u內vec[]值爲S的結點的最大深度,那麼對子樹u內兩點v1,v2,當v1與v2不在結點u的同一個兒子子樹內且vec[v1]^vec[v2]的二進制表示的1的數量不超過1時,v1到v2的路徑即爲一條經過結點u的路徑。於是我們可以在線性時間內完成對子樹u經過結點u的滿足要求的路徑的最大長度值的計算。再用啓發式合併就可以把這個暴力過程優化到O(22nlgn)。

代碼

#include<bits/stdc++.h>
using namespace std;
const int maxn=5e5+10,maxl=22,maxS=1<<22;
struct edge
{
	int u,v,d;
};
int n,ans[maxn];
int sz[maxn],t_c,st[maxn],ft[maxn],ver[maxn],vec[maxn],h[maxn],cnt[maxS];
vector<edge> e;
vector<int> G[maxn];
int idx(char c)
{
	return c-'a';
}
void add(int u,int v,int d)
{
	e.push_back((edge){u,v,d});
	int k=e.size();
	G[u].push_back(k-1);
}
void dfs1(int u,int fu,int h1)
{
	h[u]=h1;
	sz[u]=1;
	st[u]=++t_c;
	ver[t_c]=u;
	for (int i=0;i<G[u].size();i++)
	{
		edge e1=e[G[u][i]];
		int v=e1.v;
		if (v==fu) continue;
		vec[v]=vec[u]^(1<<e1.d);
		dfs1(v,u,h1+1);
		sz[u]+=sz[v];
	}
	ft[u]=t_c;
}
void dfs2(int u,int fu,bool keep)
{
	int bc=-1;
	for (int i=0;i<G[u].size();i++)
	{
		edge e1=e[G[u][i]];
		int v=e1.v;
		if (v==fu) continue;
		if (bc==-1||sz[bc]<sz[v]) bc=v;
	}
	for (int i=0;i<G[u].size();i++)
	{
		edge e1=e[G[u][i]];
		int v=e1.v;
		if (v==fu||v==bc) continue;
		dfs2(v,u,0);
	}
	if (bc!=-1) dfs2(bc,u,1),ans[u]=ans[bc];
	for (int i=0;i<G[u].size();i++)
	{
		edge e1=e[G[u][i]];
		int v=e1.v;
		if (v==fu||v==bc) continue;
		ans[u]=max(ans[u],ans[v]);
		for (int j=st[v];j<=ft[v];j++)
	    {
	    	int w=ver[j];
	    	if (cnt[vec[w]]) ans[u]=max(ans[u],cnt[vec[w]]-h[u]+h[w]-h[u]);
	    	for (int k=0;k<maxl;k++)
	    	{
	    		int S=(vec[w]^(1<<k));
	    		if (cnt[S]) ans[u]=max(ans[u],cnt[S]-h[u]+h[w]-h[u]);
			}
		}
		for (int j=st[v];j<=ft[v];j++)
		{
			int w=ver[j];
			cnt[vec[w]]=max(cnt[vec[w]],h[w]);
		}
	}
	if (cnt[vec[u]]) ans[u]=max(ans[u],cnt[vec[u]]-h[u]);
	for (int k=0;k<maxl;k++)
	{
	    int S=(vec[u]^(1<<k));
	    if (cnt[S]) ans[u]=max(ans[u],cnt[S]-h[u]);
	}
	cnt[vec[u]]=max(cnt[vec[u]],h[u]);
	if (!keep)
		for (int j=st[u];j<=ft[u];j++)
		{
			int w=ver[j];
			cnt[vec[w]]=0;
		}
}
int main()
{
	cin>>n;
	for (int i=1;i<n;i++)
	{
		int u,d;
		char ch[10];
		scanf("%d%s",&u,ch);
		d=idx(ch[0]);
		add(u,i+1,d);add(i+1,u,d);
	}
	dfs1(1,0,0);
	dfs2(1,0,0);
	for (int i=1;i<=n;i++) printf("%d ",ans[i]);
	return 0;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章