HDU 6430 Problem E. TeaTree(虚树)

Posted xcantaloupe

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了HDU 6430 Problem E. TeaTree(虚树)相关的知识,希望对你有一定的参考价值。

Problem E. TeaTree

Problem Description
Recently, TeaTree acquire new knoledge gcd (Greatest Common Divisor), now she want to test you.
As we know, TeaTree is a tree and her root is node 1, she have n nodes and n-1 edge, for each node i, it has it’s value v[i].
For every two nodes i and j (i is not equal to j), they will tell their Lowest Common Ancestors (LCA) a number : gcd(v[i],v[j]).
For each node, you have to calculate the max number that it heard. some definition:
In graph theory and computer science, the lowest common ancestor (LCA) of two nodes u and v in a tree is the lowest (deepest) node that has both u and v as descendants, where we define each node to be a descendant of itself.
Input
On the first line, there is a positive integer n, which describe the number of nodes.
Next line there are n-1 positive integers f[2] ,f[3], …, f[n], f[i] describe the father of node i on tree.
Next line there are n positive integers v[2] ,v[3], …, v[n], v[i] describe the value of node i.
n<=100000, f[i]<i, v[i]<=100000
Output
Your output should include n lines, for i-th line, output the max number that node i heard.
For the nodes who heard nothing, output -1.
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6430
题意:
一棵树上每个节点权值为v[i],每个节点的heard值是:以它为LCA的两个节点的GCD的最大值,要求输出每个节点的heard值。
树节点个数1e5,权值为最大1e5。
思路:由于权值最大才1e5,开一个1e5的vector,考虑将树节点存入它权值因子的vector(比如权值为9的结点,将他存入v[1],v[3],v[9]里),然后按照每一个vector建立一棵虚树。将这颗虚树上除了叶子的点的答案都更新。但是由于只要更新非叶子节点的值,我就直接在建立虚树边的时候更新了,省去建边和搜索的过程。
技术分享图片
  1 #include<cstdio>
  2 #include<algorithm>
  3 #include<cstring>
  4 #include<vector>
  5 #include<cmath>
  6 using namespace std;
  7 const int maxn = 100500;
  8 
  9 struct Edge       ///存原树
 10 {
 11     int to,next;
 12 } E[maxn << 1];
 13 int frist[maxn], sign = 1;
 14 inline void AddEdge(int u, int v)
 15 {
 16     E[sign].to = v;
 17     E[sign].next = frist[u];
 18     frist[u] = sign++;
 19 }
 20 
 21 /*
 22 struct void_tree  ///存虚树
 23 {
 24     int to,next;
 25 }vtree[maxn];
 26 int sign2=0,first2[maxn];
 27 inline void add_edge(int u, int v)
 28 {
 29     vtree[sign2].to = v;
 30     vtree[sign2].next = first2[u];
 31     first2[u] = sign2++;
 32 }
 33 */
 34 int dfn[maxn];   ///dfs序
 35 int deep[maxn];  ///节点深度
 36 int s[maxn];     ///
 37 int a[maxn];     ///存需要建立虚树的点
 38 int index=0;
 39 int top;         ///栈顶
 40 
 41 int fa[18][maxn];
 42 
 43 void dfs(int u)  ///预处理dep和fa[0][j]
 44 {
 45     dfn[u] = ++index;
 46     for(int i=frist[u];i;i=E[i].next)
 47     {
 48         if(E[i].to!=fa[0][u])
 49         {
 50             deep[E[i].to]=deep[u]+1;
 51             fa[0][E[i].to]=u;
 52             dfs(E[i].to);
 53         }
 54     }
 55 }
 56 inline int LCA(int u,int v)  ///求LCA
 57 {
 58     if(deep[u]>deep[v])swap(u,v);
 59     for(int i=16;~i;i--)
 60         if(deep[fa[i][v]]>=deep[u])
 61             v=fa[i][v];
 62     if(u==v)return u;
 63     for(int i=16;~i;i--)
 64         if(fa[i][u]!=fa[i][v])
 65         {
 66             u=fa[i][u];
 67             v=fa[i][v];
 68         }
 69     return fa[0][u];
 70 }
 71 int answer[maxn];
 72 
 73 inline void insert_point(int x,int num)  ///建立虚树
 74 {
 75     if(top == 0)
 76     {
 77         s[++top] = x;
 78         return ;
 79     }
 80     int lca = LCA(x, s[top]);
 81     if(lca == s[top])
 82     {
 83         s[++top]=x;
 84         return ;
 85     }
 86     while(top >= 1 && dfn[s[top - 1]] >= dfn[lca])
 87     {
 88         answer[s[top - 1]]=num;  ///不建边了,直接更新答案
 89         //add_edge(s[top - 1], s[top]);
 90         top--;
 91     }
 92     if(lca != s[top])
 93     {
 94         answer[lca]=num;
 95         //add_edge(lca, s[top]);
 96         s[top] = lca;
 97     }
 98     s[++top] = x;
 99 }
100 
101 inline int comp(const int &a, const int &b)
102 {
103     return dfn[a] < dfn[b];
104 }
105 
106 vector<int>mmp[maxn];
107 
108 int main()
109 {
110     int n,x,m;
111     memset(answer,-1, sizeof(answer));
112     memset(frist, -1, sizeof(frist));
113     scanf("%d",&n);
114     for(int i=2; i<=n; i++)
115     {
116         scanf("%d",&x);
117         AddEdge(x,i);
118     }
119 
120     deep[1]=fa[0][1]=1;
121     dfs(1);
122     for(int i=1;i<=17;i++)
123         for(int j=1;j<=n;j++)
124             fa[i][j]=fa[i-1][fa[i-1][j]];
125 
126     ///将节点存入它权值因子的vector
127     int Max = 0;
128     for(int i=1; i<=n; i++)
129     {
130         scanf("%d",&x);
131         Max = max(Max,x);
132         int temp = sqrt(x+1);
133         for(int j=1; j<=temp; j++)
134         {
135             if(x%j==0)
136             {
137                 mmp[j].push_back(i);
138                 if(j!=x/j)
139                     mmp[x/j].push_back(i);
140             }
141         }
142     }
143 
144     for(int k=1; k<=Max; k++)
145     {
146         m = mmp[k].size();
147         if(m<=1)continue;
148         for(int i = 1; i <= m; i++)a[i] = mmp[k][i-1];
149         sort(a + 1, a + m + 1, comp);
150         //memset(first2,-1,sizeof(first2));
151         top=0;
152         for(int i = 1; i <= m; i++)
153             insert_point(a[i],k);
154         while(top > 1)
155         {
156             answer[s[top - 1]]=k;           ///不建边了,直接更新答案
157             //add_edge(s[top - 1], s[top]);
158             top--;
159         }
160         //dfs(s[top]);                      ///省去dfs
161     }
162     for(int i=1;i<=n;i++)
163         printf("%d
",answer[i]);
164     return 0;
165 }
View Code

 

以上是关于HDU 6430 Problem E. TeaTree(虚树)的主要内容,如果未能解决你的问题,请参考以下文章

2018多校第十场 HDU 6430 线段树合并

杭电2018多校第四场(2018 Multi-University Training Contest 4) 1005.Problem E. Matrix from Arrays (HDU6336) -

Problem E. Matrix from Arrays(杭电2018年多校第四场+思维+打表找循环节)

hdu多校第4场E. Matrix from Arrays HDU 二维前缀和

codeforces 291 E. Tree-String Problem (dfs+kmp)

Gym-101194E Problem E. Bet