CF2223C 思路分享(数论)
https://codeforces.com/problemset/problem/2223/C
题意
给定一棵 \(n\) 个节点的树,根为 \(1\),每条边有边权 \(w\),走过这条边需要 \(w\) 时间.
当时间为 \(T\) 时,节点 \(u\) 的指示节点为 \(u\) 的第 \(T \mod d + 1\) 个孩子,\(d\) 是 \(u\) 的孩子数量.
给定 \(q\) 个询问,每个询问给定初始时间 \(m_i\),求从根出发沿着指示节点最后会到达的节点.
\(1\le n \le 5\cdot 10^5\),\(1\le q \le 10^6\),\(0\le m_i \le 10^{18}\).
思路
假如当前时间为 \(T\),在节点 \(u_1\),则
\[\begin{cases}
T \equiv r_1 \pmod{deg_{u_1}} \\
(T+w_{u_1,r_1}) \equiv r_2 \pmod{deg_{u_2}} \\
\cdots
\end{cases}
\]
后面项都可以化成与第一项类似的形式,发现本质是解同余方程,启发我们用类似拓展中国剩余定理的形式维护询问.
对于节点 \(u\),维护会到达 \(u\) 的所有询问,距离 \(dis\),以及二元组 \((M,r)\),会到达 \(u\) 的所有询问满足
\[m_i \equiv r \pmod M
\]
- 若 \(M\gt 10^{18}\) 或 \(deg_u \mid M\),则
\[(m_i+dis)\mod {deg_u} = (r+dis)\mod {deg_u}
\]
为定值,所有询问会前往相同的孩子.
- 否则维护的询问会分裂,将 \(M\) 迭代成 \(lcm(M,deg_u)\),同时调整 \(r\).
每次分裂,\(M\) 至少会 \(\times 2\),因此分裂次数是 \(log\) 级别的.
时间复杂度 \(\mathcal{O}(n \log V)\),\(V\) 是 \(m_i\) 的值域.
代码
//author:kzssCCC
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
using i128 = __int128;
const ll INF = 1e18;
const ll MOD = 1e18+7;
ll lcm(ll a,ll b){
i128 temp = (i128)a/__gcd(a,b)*b;
if (temp>INF){
return MOD;
}
else{
return temp;
}
}
void solve(){
int n,q;
cin >> n >> q;
vector<int> F(n+1);
vector<ll> L(n+1);
vector<vector<pair<ll,int>>> adj(n+1);
for (int i=2;i<=n;i++){
cin >> F[i];
}
for (int i=2;i<=n;i++){
cin >> L[i];
adj[F[i]].emplace_back(L[i],i);
}
for (int i=1;i<=n;i++){
sort(adj[i].begin(),adj[i].end(),[&](auto& p1,auto& p2){
return p1.second < p2.second;
});
}
vector<ll> m(q+1);
for (int i=1;i<=q;i++){
cin >> m[i];
}
vector<int> res(q+1);
function<void(int,ll,ll,ll,vector<int>&)> dfs = [&](int u,ll dis,ll M,ll r,vector<int>& Q){
int deg = adj[u].size();
if (deg==0){
for (auto& i:Q){
res[i] = u;
}
return;
}
if (M>INF || M%deg==0){
dfs(adj[u][(r+dis)%deg].second,dis+adj[u][(r+dis)%deg].first,M,r,Q);
}
else{
vector<vector<int>> temp(deg);
for (auto& i:Q){
temp[(m[i]+dis)%deg].push_back(i);
}
for (int i=0;i<deg;i++){
if (temp[i].empty()) continue;
auto& [w,v] = adj[u][i];
ll nM = lcm(M,deg);
dfs(v,dis+w,nM,m[temp[i][0]]%nM,temp[i]);
}
}
};
{
vector<int> temp(q);
iota(temp.begin(),temp.end(),1);
dfs(1,0,1,0,temp);
}
for (int i=1;i<=q;i++){
cout << res[i] << ' ';
}
cout << '\n';
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
int t = 1;
cin >> t;
while (t--) solve();
return 0;
}

浙公网安备 33010602011771号