【题解】CF741D(DSU on TREE)

【题解】CF741D(DSU on TREE)

写一写这道题来学习学习模板

用二进制来转换一下条件,现在就是要求一下\(lowbit(x)=x\)的那些路径了。

DSU on TREE 是这样一种算法:

  • 像树剖一样分出轻重链,根据那套理论可知轻边\(O(\log n)\)
  • 递归处理一个节点的所有轻儿子,并且回溯的时候将统计信息清空。
  • 递归处理一个节点的那个重儿子,并且回溯的时候保留统计信息。
  • 获得重儿子信息后,遍历一下所有轻儿子统计答案。

分析复杂度:对于每个点,可以被他父亲所有的轻边多遍历一次。复杂度\(O(tn \log n)\)\(t\)是加入一个信息需要的复杂度。

具体到这道题的话,就是开桶记录该二进制状态下最深深度点的深度。取\(max\)就好

//@winlere
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>

using namespace std;  typedef long long ll;
inline int qr(){
      register int ret=0,f=0;
      register char c=getchar();
      while(c<48||c>57)f|=c==45,c=getchar();
      while(c>=48&&c<=57) ret=ret*10+c-48,c=getchar();
      return f?-ret:ret;
}

char c;
const int maxn=5e5+5,inf=1e9;
int d[maxn],cnt[1<<22|1],n,siz[maxn],son[maxn],dfn[maxn],End[maxn],arc[maxn];
int ans[maxn],dis[maxn];
vector< pair<int,int> > e[maxn];
inline void add(const int&fr,const int&to,const int&w){
      e[fr].push_back({to,1<<w});
}

void predfs(const int&now){
      siz[now]=1;
      dfn[now]=++*dfn;
      arc[*dfn]=now;
      for(auto t:e[now])
	    d[t.first]=d[now]^t.second,dis[t.first]=dis[now]+1,predfs(t.first),siz[now]+=siz[t.first],son[now]=siz[t.first]>siz[son[now]]?t.first:son[now];
      End[now]=*dfn;
}

void dfs(const int&now,const int&keep){
      for(auto t:e[now])
	    if(t.first^son[now])
		  dfs(t.first,0),ans[now]=max(ans[now],ans[t.first]);
      if(son[now]) dfs(son[now],1),ans[now]=max(ans[now],ans[son[now]]);
      if(cnt[d[now]]) ans[now]=max(ans[now],cnt[d[now]]-dis[now]);
      for(int t=0;t<22;++t)
	    if(cnt[d[now]^(1<<t)])
		  ans[now]=max(ans[now],cnt[d[now]^(1<<t)]-dis[now]);
      cnt[d[now]]=max(cnt[d[now]],dis[now]);
      for(auto T:e[now])
	    if(T.first^son[now]){
		  for(int t=dfn[T.first];t<=End[T.first];++t){
			if(cnt[d[arc[t]]])
			      ans[now]=max(ans[now],cnt[d[arc[t]]]+dis[arc[t]]-dis[now]*2);
			for(int i=0;i<22;++i)
			      if(cnt[d[arc[t]]^(1<<i)])
				    ans[now]=max(ans[now],cnt[d[arc[t]]^(1<<i)]+dis[arc[t]]-dis[now]*2);
		  }
		  for(int t=dfn[T.first];t<=End[T.first];++t)
			cnt[d[arc[t]]]=max(cnt[d[arc[t]]],dis[arc[t]]);
	    }
      if(!keep) for(int t=dfn[now];t<=End[now];++t) cnt[d[arc[t]]]=0;
}

int main(){
      n=qr();
      for(int t=2,t1;t<=n;++t){
	    t1=qr();
	    char c=getchar();
	    while(c<'a'||c>'z') c=getchar();
	    add(t1,t,c-'a');
      }
      predfs(1);
      dfs(1,0);
      for(int t=1;t<=n;++t) printf("%d ",ans[t]);
      putchar('\n');
      return 0;
}

posted @ 2019-09-18 22:25  谁是鸽王  阅读(369)  评论(0编辑  收藏  举报