zoukankan      html  css  js  c++  java
  • $CF741D$题解

    这是一道好题……

    关于这篇文章我为什么不和(dsu) (on) (tree)放一起,因为这题太好了,单独拿出来会好些

    这是可爱的链接

    先大致扫一眼题意,发现一条路径满足条件,当且仅当上面至多有一种字母出现次数为奇数次,总共有(22)种,因此我们可以考虑状压,(0)表示一个字母出现偶数次,(1)表示出现奇数次,用异或处理即可。

    再看一下题目,很像一道点分治的题(真的,树上路径你告诉我不像?)但是这道题是一颗定根树,树根为(1)

    显然不能点分治,但是点分治的思路可以借鉴一下,考虑树上启发式合并(dsu) (on) (tree)

    即在做答案时用点分治的方式做(一条路径可行的情况只有(23)种),维护信息时用树上启发式合并的方法取维护。

    我们维护一个(f[x])表示从根节点出发路径异或之后的值为(x)的最大深度。

    这一题因为用到了点分治的思路,所以相当于我们做答案时是先算了(x)的每个子树的答案,在考虑所有过(x)的路径,因此我们在(dsu) (on) (tree)上做答案时递归需要保留(x)(但这种情况我还没改出来,有知道的怎么改的跟我讲一下好吗?)

    #include<bits/stdc++.h>
    using namespace std;
    inline int read()
    {
        int f=1,w=0;char x=0;
        while(x<'0'||x>'9') {if(x=='-') f=-1; x=getchar();}
        while(x!=EOF&&x>='0'&&x<='9') {w=(w<<3)+(w<<1)+(x^48);x=getchar();}
        return w*f;
    }
    const int N=500010;
    int num_edge,n,Tim,Id[N];
    int head[N],Dep[N],Xor[N],f[1<<22],End[N];
    int Vis[N],Siz[N],Max[N],ans[N],Dfn[N];
    struct Edge{int next,to,dis;} edge[N];
    inline void Add(int from,int to,int dis)
    {
    	edge[++num_edge].next=head[from];
    	edge[num_edge].dis=dis;
    	edge[num_edge].to=to;
    	head[from]=num_edge;
    }
    inline void Dfs_For_Pre(int pos,int fth,int dis)
    {
    	Dfn[pos]=++Tim,Id[Dfn[pos]]=pos;Siz[pos]=1;
    	Dep[pos]=Dep[fth]+1;Xor[pos]=Xor[fth]^dis;
    	for(int i=head[pos];i;i=edge[i].next)
    	{
    		Dfs_For_Pre(edge[i].to,pos,edge[i].dis);
    		Siz[pos]+=Siz[edge[i].to];
    		if(Siz[Max[pos]]<Siz[edge[i].to]) Max[pos]=edge[i].to;
    	}
    	End[pos]=Tim;
    }
    /*inline void Update(int pos,int Anc)
    {
    	if(f[Xor[pos]]) ans[Anc]=max(ans[Anc],f[Xor[pos]]+Dep[pos]-(Dep[Anc]<<1));
    	for(int j=0;j<22;j++)
    		if(f[Xor[pos]^(1<<j)])
    			ans[Anc]=max(ans[Anc],f[Xor[pos]^(1<<j)]+Dep[pos]-(Dep[Anc]<<1));
    	for(int i=head[pos];i;i=edge[i].next)
    		if(!Vis[edge[i].to]) Update(edge[i].to,Anc);
    }
    inline void Cancel(int pos)
    {
    	for(int i=head[pos];i;i=edge[i].next)
    		f[Xor[edge[i].to]]=0,Cancel(edge[i].to);
    }
    inline void Change(int pos)
    {
    	for(int i=head[pos];i;i=edge[i].next)
    		f[Xor[edge[i].to]]=max(f[Xor[edge[i].to]],Dep[edge[i].to]),Change(edge[i].to);
    }
    inline void Dsu_On_Tree(int pos,int Jud)
    {
    	for(int i=head[pos];i;i=edge[i].next)
    		if(edge[i].to!=Max[pos])
    			Dsu_On_Tree(edge[i].to,0),ans[pos]=max(ans[pos],ans[edge[i].to]);
    	if(Max[pos]) Dsu_On_Tree(Max[pos],1),ans[pos]=max(ans[pos],ans[Max[pos]]),Vis[Max[pos]]=1;
    	
    	if(f[Xor[pos]]) ans[pos]=max(ans[pos],f[Xor[pos]]-Dep[pos]);
    	for(int i=0;i<22;i++)
    		if(f[Xor[pos]^(1<<i)]) ans[pos]=max(ans[pos],f[Xor[pos]^(1<<i)]-Dep[pos]);
    	f[Xor[pos]]=max(f[Xor[pos]],Dep[pos]);
    	
    	for(int i=head[pos];i;i=edge[i].next)
    		if(!Vis[edge[i].to]) Update(edge[i].to,pos),Change(edge[i].to);
    	Vis[Max[pos]]=0;if(!Jud) f[Xor[pos]]=0,Cancel(pos);
    }
    */
    inline void Dsu_On_Tree(int pos,int Jud)
    {
    	for(int i=head[pos];i;i=edge[i].next)
    		if(edge[i].to!=Max[pos])
    			Dsu_On_Tree(edge[i].to,0),ans[pos]=max(ans[pos],ans[edge[i].to]);
    	if(Max[pos]) Dsu_On_Tree(Max[pos],1),ans[pos]=max(ans[pos],ans[Max[pos]]);
    	
    	if(f[Xor[pos]]) ans[pos]=max(ans[pos],f[Xor[pos]]-Dep[pos]);
    	for(int i=0;i<22;i++)
    		if(f[Xor[pos]^(1<<i)]) ans[pos]=max(ans[pos],f[Xor[pos]^(1<<i)]-Dep[pos]);
    	f[Xor[pos]]=max(f[Xor[pos]],Dep[pos]);
    
    	for(int i=head[pos];i;i=edge[i].next)
    		if(edge[i].to!=Max[pos])
    		{
    			for(int j=Dfn[edge[i].to];j<=End[edge[i].to];j++)
    			{
    				if(f[Xor[Id[j]]]) ans[pos]=max(ans[pos],f[Xor[Id[j]]]+Dep[Id[j]]-(Dep[pos]<<1));
    				for(int k=0;k<22;k++)
    					if(f[Xor[Id[j]]^(1<<k)]) ans[pos]=max(ans[pos],f[Xor[Id[j]]^(1<<k)]+Dep[Id[j]]-(Dep[pos]<<1));
    			}
    			for(int j=Dfn[edge[i].to];j<=End[edge[i].to];j++)
    				f[Xor[Id[j]]]=max(f[Xor[Id[j]]],Dep[Id[j]]);
    		}
    	if(!Jud) for(int j=Dfn[pos];j<=End[pos];j++) f[Xor[Id[j]]]=0;
    }
    int main(){
    #ifndef ONLINE_JUDGE
        //freopen("A.in","r",stdin);//Ans=3 1 1 0 
        freopen("B.in","r",stdin);//Ans=4 1 0 1 0 
    #endif
    	char c;n=read();
    	for(int i=2,x;i<=n;i++)
    		x=read(),c=getchar(),Add(x,i,1<<(c-'a'));
    	Dfs_For_Pre(1,0,0);Dsu_On_Tree(1,0);
    	for(int i=1;i<=n;i++) printf("%d ",ans[i]);
    }
    
  • 相关阅读:
    SettingWithCopyWarning
    统计运算
    数据清洗
    dataframe 索引
    那些拯救我的快捷键
    如何拒绝那些哭天抢地向你求救结果把你坑了的同事?
    Linux 笔记
    数据可视化:桑基图
    敏捷
    持续集成的概念
  • 原文地址:https://www.cnblogs.com/wo-shi-zhen-de-cai/p/11535026.html
Copyright © 2011-2022 走看看