CF741DArpa’s letter-marked tree and Mehrdad’s Dokhtar-kosh paths(DSU on tree)

题目大意:

  给定一个以1为根的树,每条路径上都有一个字符(a~v共22个)询问对于每一个子树内最长的路径上字母经排序后可以形成回文串的最长路径多长

解题思路:

  假定给你一个字符串,如何判定其经打乱能否形成回文串,那就是说所有字符中最多只有一个能出现奇数次,22个字符,可以用2进制表示每个字符出现的次数奇偶性,1为奇0为偶,那么处理出一个点到根节点路径上的异或和(设为xi),如果两个节点i,j的xi=xj那么就说明这两个点的路径上符合要求。

  暴力的思路:暴力搜索一棵树中所有的xi看看有没有相同或差一位的再进行答案更新。

  考虑优化,既然是不同子树中的点,那么就可以用一个数组存起来异或和为x的最大深度maxdeep[x],每次进去找,找完再把整颗子树推进去。这样就是O(n2)

  这样就可以用DSU了,每次处理子树时,最后处理重儿子,非重儿子直接推倒,在更新上层时直接在重儿子版本上构建数组,再重建轻儿子,注意更新答案时要更新为子树最大值,跨字数最大值,返祖链最大值中的最大值。时间复杂度O(nlogn)

  DSU还是十分优秀啊

  代码:

  1 #include<cstdio>
  2 #include<cstring>
  3 #include<algorithm>
  4 struct pnt{
  5     int hd;
  6     int dp;
  7     int wgt;
  8     int mxs;
  9     int ans;
 10     int xr;
 11 }p[1000000];
 12 struct ent{
 13     int twd;
 14     int lst;
 15     int vls;
 16 }e[1000000];
 17 int n;
 18 int cnt;
 19 char cmd[100];
 20 int mxdp[10000000];
 21 void ade(int f,int t,int v)
 22 {
 23     cnt++;
 24     e[cnt].twd=t;
 25     e[cnt].lst=p[f].hd;
 26     e[cnt].vls=v;
 27     p[f].hd=cnt;
 28 }
 29 void Basic_dfs(int x,int f)
 30 {
 31     p[x].dp=p[f].dp+1;
 32     p[x].wgt=1;
 33     int maxs=-1;
 34     for(int i=p[x].hd;i;i=e[i].lst)
 35     {
 36         int to=e[i].twd;
 37         p[to].xr=p[x].xr^e[i].vls;
 38         Basic_dfs(to,x);
 39         p[x].wgt+=p[to].wgt;
 40         if(maxs<p[to].wgt)
 41         {
 42             maxs=p[to].wgt;
 43             p[x].mxs=to;
 44         }
 45     }
 46 }
 47 void Build_dfs(int x)
 48 {
 49     mxdp[p[x].xr]=std::max(mxdp[p[x].xr],p[x].dp);
 50     for(int i=p[x].hd;i;i=e[i].lst)
 51         Build_dfs(e[i].twd);
 52 }
 53 void Destory_dfs(int x)
 54 {
 55     mxdp[p[x].xr]=0;
 56     for(int i=p[x].hd;i;i=e[i].lst)
 57         Destory_dfs(e[i].twd);
 58 }
 59 void Ans_dfs(int x,int a)
 60 {
 61     if(mxdp[p[x].xr])
 62         p[a].ans=std::max(p[a].ans,p[x].dp+mxdp[p[x].xr]-2*p[a].dp);
 63     for(int i=0;i<22;i++)
 64     {
 65         int tmp=1<<i;
 66         if(mxdp[p[x].xr^tmp])
 67             p[a].ans=std::max(p[a].ans,p[x].dp+mxdp[p[x].xr^tmp]-2*p[a].dp);
 68     }
 69     for(int i=p[x].hd;i;i=e[i].lst)
 70         Ans_dfs(e[i].twd,a);
 71 }
 72 void DSU_dfs(int x,bool hvs)
 73 {
 74     for(int i=p[x].hd;i;i=e[i].lst)
 75     {
 76         int to=e[i].twd;
 77         if(to==p[x].mxs)
 78             continue;
 79         DSU_dfs(to,false);
 80         p[x].ans=std::max(p[x].ans,p[to].ans);
 81     }
 82     if(p[x].mxs)
 83     {
 84         DSU_dfs(p[x].mxs,true);
 85         p[x].ans=std::max(p[x].ans,p[p[x].mxs].ans);
 86     }
 87     if(mxdp[p[x].xr])
 88         p[x].ans=std::max(p[x].ans,mxdp[p[x].xr]-p[x].dp);
 89     for(int i=0;i<22;i++)
 90     {
 91         int tmp=1<<i;
 92         if(mxdp[p[x].xr^tmp])
 93             p[x].ans=std::max(p[x].ans,mxdp[p[x].xr^tmp]-p[x].dp);
 94     }
 95     mxdp[p[x].xr]=std::max(p[x].dp,mxdp[p[x].xr]);
 96     for(int i=p[x].hd;i;i=e[i].lst)
 97     {
 98         int to=e[i].twd;
 99         if(to==p[x].mxs)
100             continue;
101         Ans_dfs(to,x);
102         Build_dfs(to);
103     }
104     if(hvs)
105         return ;
106     Destory_dfs(x);
107 }
108 int main()
109 {
110     scanf("%d",&n);
111     for(int i=2;i<=n;i++)
112     {
113         int x;
114         scanf("%d",&x);
115         scanf("%s",cmd);
116         int tmp=1<<(cmd[0]-'a');
117         ade(x,i,tmp);
118     }
119     Basic_dfs(1,1);
120     DSU_dfs(1,true);
121     for(int i=1;i<=n;i++)
122         printf("%d ",p[i].ans);
123     puts("");
124     return 0;
125 }

猜你喜欢

转载自www.cnblogs.com/blog-Dr-J/p/9563432.html