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

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6430

题意:一棵树上每个节点权值为v[i],每个节点的heard值是:以它为LCA的两个节点的GCD的最大值,要求输出每个节点的heard值。

题解:权值范围是[1, 1e5],1e5内数因子最多不超过200个,对每个点建一颗线段树,维护每个点的因子,dfs过程中由下往上合并线段树并更新答案。

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 #define ll long long
 4 #define ull unsigned long long
 5 #define mst(a,b) memset((a),(b),sizeof(a))
 6 #define mp(a,b) make_pair(a,b)
 7 #define fi first
 8 #define se second
 9 #define pi acos(-1)
10 #define pii pair<int,int>
11 #define pb push_back
12 const int INF = 0x3f3f3f3f;
13 const double eps = 1e-6;
14 const int MAXN = 1e5 + 10;
15 const int MAXM = 2e6 + 10;
16 const ll mod = 1e9 + 7;
17
18 vector<int>yz[MAXN],vec[MAXN];
19
20 void init() {
21     for(int i = 1; i < MAXN; i++) {
22         for(int j = 1; j <= sqrt(i); j++) {
23             if(i % j == 0) {
24                 yz[i].pb(j);
25                 if(j != i / j) yz[i].push_back(i / j);
26             }
27         }
28     }
29 }
30
31 int root[MAXN];
32 int ls[MAXN * 400], rs[MAXN * 400], st[MAXN * 400];
33 int cnt = 0;
34
35 void pushup(int o) {
36     st[o] = max(st[ls[o]], st[rs[o]]);
37 }
38
39 void update(int k,int l,int r,int &o) {
40     if(!o) o = ++cnt;
41     if(l == r) {
42         st[o] = k;
43         return ;
44     }
45     int mid = (l + r) >> 1;
46     if(k <= mid) update(k, l, mid, ls[o]);
47     else update(k, mid + 1, r, rs[o]);
48     pushup(o);
49 }
50
51 int mergee(int fa,int u,int &ans) {
52     if(!fa || !u) return fa | u;
53     if(st[fa] == st[u]) ans = max(ans, st[fa]);
54     if(ls[fa] || ls[u]) ls[fa] = mergee(ls[fa], ls[u], ans);
55     if(rs[fa] || rs[u]) rs[fa] = mergee(rs[fa], rs[u], ans);
56     return fa;
57 }
58
59 int ans[MAXN];
60
61 void dfs(int u) {
62     for(int i = 0; i < vec[u].size(); i++) {
63         int v = vec[u][i];
64         dfs(v);
65         mergee(root[u], root[v], ans[u]);
66     }
67 }
68
69 int main() {
70 #ifdef local
71     freopen("data.txt", "r", stdin);
72 //    freopen("data.txt", "w", stdout);
73 #endif
74     init();
75     int n;
76     scanf("%d",&n);
77     for(int i = 2; i <= n; i++) {
78         int f;
79         scanf("%d",&f);
80         vec[f].push_back(i);
81     }
82     for(int i = 1; i <= n; i++) {
83         int x;
84         scanf("%d",&x);
85         for(int j = 0; j < yz[x].size(); j++)
86             update(yz[x][j], 1, 1e5, root[i]);
87     }
88     mst(ans, -1);
89     dfs(1);
90     for(int i = 1; i <= n; i++)
91         printf("%d\n",ans[i]);
92     return 0;
93 }

原文地址:https://www.cnblogs.com/scaulok/p/9580565.html

时间: 2024-08-28 18:31:48

2018多校第十场 HDU 6430 线段树合并的相关文章

2014多校第十场1004 || HDU 4974 A simple water problem

题目链接 题意 : n支队伍,每场两个队伍表演,有可能两个队伍都得一分,也可能其中一个队伍一分,也可能都是0分,每个队伍将参加的场次得到的分数加起来,给你每个队伍最终得分,让你计算至少表演了几场. 思路 : ans = max(maxx,(sum+1)/2) :其实想想就可以,如果所有得分中最大值没有和的一半大,那就是队伍中一半一半对打,否则的话最大的那个就都包了. 1 #include <cstdio> 2 #include <cstring> 3 #include <st

多校第六场 HDU 4927 JAVA大数类

题目大意:给定一个长度为n的序列a,每次生成一个新的序列,长度为n-1,新序列b中bi=ai+1?ai,直到序列长度为1.输出最后的数. 思路:这题实在是太晕了,比赛的时候搞了四个小时,从T到WA,唉--对算组合还是不太了解啊,现在对组合算比较什么了-- import java.io.*; import java.math.*; import java.util.*; public class Main { public static void main(String[] args) { Sca

2014多校第六场 || HDU 4927 Series 1(杨辉三角组合数)

题目链接 题意 : n个数,每操作一次就变成n-1个数,最后变成一个数,输出这个数,操作是指后一个数减前一个数得到的数写下来. 思路 : 找出几个数,算得时候先不要算出来,用式子代替,例如: 1 2 3 4 5 6 (2-1) (3-2) (4-3) (5-4)(6-5) (3-2-2+1)(4-3-3+2)(5-4-4+3)(6-5-5+4) (4-3-3+2-3+2+2-1)(5-4-4+3-4+3+3-2)(6-5-5+4-5+4+4-3) (5-4-4+3-4+3+3-2-4+3+3-2

多校第4场 HDU 4902 Nice boat 线段树

思路:这题比赛的时候宝哥说的思路我觉得对的,就是当是2操作的时候,先把数放到数组里,最后查询输出的时候再统一计算,不过那时敲得烂死了,debug了两天,靠-- 上午写的vector在pushDown的时候又忘了clear了,然后MLE了一早上,尼玛,还以为用的数组太大超了,然后又改成结构体,还是MLE,最后把别人的代码交上去发现没MLE,疯了一中午,最后无聊的时候才发现这个错误,尼玛--发现自己调试怎么变得这么弱了呢-- 还有一个需要注意的问题是1与2操作的处理上比较容易出错,这也是我WA了一下

2017多校第8场 HDU 6133 Army Formations 线段树合并

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6133 题意:给你一棵n个节点的二叉树,每个节点有一个提交任务的时间,每个节点总的提交任务的罚时为:提交这个节点和其子树所有的任务,每个任务提交时间的总和为该点的罚时.求每个节点提交完所有任务的最小罚时. 解法:根据题意,我们可以知道每个节点的提交的最小罚时为,按照任务的提交时间从小到大的来提交任务,可以得到最小的罚时.所以我们可以用线段树合并,先建立权值线段树,记录权值区间L到R的所有权值sum与s

hdu 2795 线段树--点更新

http://acm.hdu.edu.cn/showproblem.php?pid=2795 多校的第一场和第三场都出现了线段树,比赛期间没做,,这两天先做几道热身下,然后31号之前把那两道多校的线段树都搞了,这是一道热身题 关键是建模: 首先一定看清楚题目构造的场景,看有什么特点--------会发现,如果尽量往左上放置的话,那么由于 the i-th announcement is a rectangle of size 1 * wi.,完全可以对h建立线段树,表示一行,结点里的l,r就表示

HDU 4893 线段树裸题

Wow! Such Sequence! Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Total Submission(s): 2512    Accepted Submission(s): 751 Problem Description Recently, Doge got a funny birthday present from his new friend, Pro

HDU 4902 线段树(区间更新)

Nice boat Time Limit: 30000/15000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others)Total Submission(s): 353    Accepted Submission(s): 169 Problem Description There is an old country and the king fell in love with a devil. The devil alw

hdu 4893 线段树 --- 也是两个变 类似双标记

http://acm.hdu.edu.cn/showproblem.php?pid=4893 开始的时候,我按双标记,WA了一下午,搞不定,我是用的两个标记add--表示当前结点中有值发生变化,flag,斐波那契的懒惰标记,但是估计是我自己处理的有问题,一直不对 参考了别人的代码,写法还是很不错的,Add变量维护的是,完全变成Fibonacci的时候的和,---回头我再重新写一遍 #include <cstdio> #include <cstring> #include <a