[HDU 6430] 2018 Multi-University Training Contest 10 Problem E. TeaTree 暴力 bitset
阿新 • • 發佈:2019-01-29
題目大意
一顆樹, 每個節點上有一個小於等於1e5的數字, 然後每個節點的值等於所有以它為LCA 的節點對(i, j)中gcd(v[i], v[j])的最大值, 要求輸出所有節點的值
思路
一開始想到用bitset記錄每個節點的所有因數, 但TLE了, 沒想到G++的bitset有一個函式叫做_Find_first()
能玄學地快速找到為1的最低位, 賽後改用這個函式就AC了
具體思路是後序遍歷這棵樹, 這樣可以保證訪問某節點時, 它的所有子節點都已經訪問過了, 然後每個節點用一個bitset記錄它和它的所有子節點所有因子(要預處理[1, 1e5]所有數字的所有因子)
一開始將節點的bitset設定為本結點v[i]的因子情況, 然後以當前節點為LCA的節點對, 要麼是一個為本節點, 一個為其子節點, 要麼兩個來自其不同的兩個子節點, 兩個bitset相與就能得到其所有公因子, 取最大的一個就是答案
因為每次只需要用的當前節點和其直接子節點的bitset, 當我們處理完當前節點後, 將其所有子節點的bitset刪除, 否則會TLE
要求最大的公因子(即bitset最高的1位置), _Find_first()
程式碼
Accepted 6430 1107MS 18604K 1633 B G++
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e5 + 100, mod = 1e9 + 7, sqrn = 320;
int n;
struct edge
{
int from, to, nxt;
};
edge es[maxn];
int head[maxn];
vector <int> divisor[maxn];
inline void addedge(int id, int from, int to)
{
es[id].from = from;
es[id].to = to;
es[id].nxt = head[from];
head[from] = id;
}
bitset<maxn> *bitv[maxn];
int f[maxn], v[maxn];
int ans[maxn];
void dfs(int u)
{
for(int i=head[u]; i; i=es[i].nxt)
{
int v=es[i].to;
dfs(v);
}
bitv[u] = new bitset<maxn>(0);
for(auto &ite : divisor[v[u]])
{
(*bitv[u])[maxn-1-ite] = 1;
}
int x;
for(int i=head[u]; i; i=es[i].nxt)
{
int v = es[i].to;
x = ((*bitv[u]) & (*bitv[v]))._Find_first();
if(x<maxn) ans[u] = max(maxn-1-x, ans[u]);
(*bitv[u]) |= (*bitv[v]);
}
for(int i=head[u]; i; i=es[i].nxt)
{
int v = es[i].to;
delete bitv[v];
}
}
int main()
{
for (int i = 1; i < maxn; ++i)
{
for (int j = i; j < maxn; j += i) divisor[j].push_back(i);
}
scanf("%d", &n);
for(int i=2; i<=n; ++i) scanf("%d", f+i);
for(int i=1; i<=n; ++i) scanf("%d", v+i);
for(int i=2; i<=n; ++i)
{
addedge(i, f[i], i);
}
dfs(1);
for(int i=1; i<=n; ++i)
{
if(ans[i] == 0) printf("-1\n");
else printf("%d\n", ans[i]);
}
return 0;
}