zoukankan      html  css  js  c++  java
  • 【CF741D】Arpa’s lettermarked tree and Mehrdad’s Dokhtarkosh paths

    题目

    题目链接:https://codeforces.ml/problemset/problem/741/D
    一棵根为 \(1\) 的树,每条边上有一个字符( \(a\sim v\)\(22\) 种)。一条简单路径被称为 Dokhtar-kosh 当且仅当路径上的字符经过重新排序后可以变成一个回文串。 求每个子树中最长的 Dokhtar-kosh 路径的长度。

    思路

    明显地要把一条路径之间所有字母状压,然后一条路径是 Dk 路径当且仅当状压后最多包含一个 \(1\)
    \(a[x]\) 表示点 \(x\) 到根的路径中字母的状态,那么对于一条 \(u\)\(v\) 的路径,其状态就是 \(a[u]\operatorname{xor} a[v]\)
    \(maxd[s]\) 表示当前搜索到的子树中状态为 \(s\) 的点最深的深度,每次计算答案的时候枚举状态为 \(1\) 的字母,乱搞即可。
    直接上 dsu on tree。时间复杂度 \(O(nm\log n)\),其中 \(m\) 是字母数(即 \(22\))。

    代码

    #include <bits/stdc++.h>
    using namespace std;
    
    const int N=500010,M=(1<<22)+10;
    int n,tot,head[N],a[N],son[N],size[N],maxd[M],dep[N],ans[N],dfn[N],id[N];
    char ch[5];
    
    struct edge
    {
    	int next,to;
    }e[N];
    
    void add(int from,int to)
    {
    	e[++tot].to=to;
    	e[tot].next=head[from];
    	head[from]=tot;
    }
    
    void dfs1(int x,int fa)
    {
    	dep[x]=dep[fa]+1; size[x]=1;
    	a[x]^=a[fa]; dfn[x]=++tot; id[tot]=x;
    	for (int i=head[x];~i;i=e[i].next)
    	{
    		int v=e[i].to;
    		dfs1(v,x);
    		size[x]+=size[v];
    		if (size[v]>size[son[x]]) son[x]=v;
    	}
    }
    
    void update(int &WYCTQL,int v,int x,int p)
    {
    	if (maxd[v]) WYCTQL=max(WYCTQL,maxd[v]+dep[x]-2*dep[p]);
    	for (int i=0;i<22;i++)
    		if (maxd[v^(1<<i)]) WYCTQL=max(WYCTQL,maxd[v^(1<<i)]+dep[x]-2*dep[p]);
    }
    
    void dfs2(int x,bool clr)
    {
    	for (int i=head[x];~i;i=e[i].next)
    	{
    		int v=e[i].to;
    		if (v!=son[x])
    			dfs2(v,1),ans[x]=max(ans[x],ans[v]);
    	}
    	if (son[x])
    	{
    		dfs2(son[x],0);
    		ans[x]=max(ans[x],ans[son[x]]);
    	}
    	update(ans[x],a[x],x,x);
    	maxd[a[x]]=max(maxd[a[x]],dep[x]);
    	for (int i=head[x];~i;i=e[i].next)
    	{
    		int v=e[i].to;
    		if (v!=son[x])
    		{
    			for (int j=dfn[v];j<dfn[v]+size[v];j++)
    				update(ans[x],a[id[j]],id[j],x);
    			for (int j=dfn[v];j<dfn[v]+size[v];j++)
    				maxd[a[id[j]]]=max(maxd[a[id[j]]],dep[id[j]]);
    		}
    	}
    	if (clr)
    		for (int i=dfn[x];i<dfn[x]+size[x];i++)
    			maxd[a[id[i]]]=0;
    }
    
    int main()
    {
    	memset(head,-1,sizeof(head));
    	scanf("%d",&n);
    	for (int i=2,x;i<=n;i++)
    	{
    		cin>>x>>ch;
    		add(x,i);
    		a[i]=1<<(ch[0]-'a');
    	}
    	tot=0;
    	dfs1(1,0); dfs2(1,0);
    	for (int i=1;i<=n;i++)
    		printf("%d ",ans[i]);
    	return 0;
    }
    
  • 相关阅读:
    ADO 缓存更新
    DBNavigator中把insert变为append
    JQuery 选择器
    VS2013默认打开HTML文件没有设计视图
    windows 关机 重启 命令
    java如何计算两个日期之间相差多少天?
    java的list集合操作List<T>转化List<Long>
    ExcelUtil工具类
    oracle的START WITH CONNECT BY PRIOR用法
    oracle的with as用法
  • 原文地址:https://www.cnblogs.com/stoorz/p/13763925.html
Copyright © 2011-2022 走看看