ZR#959

解法:

对于一个询问,设路径 $ (u, v) $ 经过的所有边的 $ gcd $ 为 $ g $,这可以倍增求出。

考虑 $ g $ 的所有质因子 $ p_1, p_2, \cdots , p_k $ ,因为 $ g \leq 10^6 $ ,所以 $ k \leq 7 $ 。

则最终的路径的 $ gcd $ 为 $ 1 $,等价于对于每个 $ 1 \leq i \leq k $ ,存在至少一条路径上的边不是 $ p_i $ 的倍数。我们要求 $ l $ 的最小值,即等价于对于每个 $ 1 \leq i \leq k $ ,计算出最长的不满足条件的 $ l′ $,则最终答案即为所有 $ i $ 对应的 $ l′ $ 的最大值加一(无解的情况除外)。

考虑对于某个 $ p_i $ 而言,我们如何求出这样的 $ l′ $ 。我们考虑将所有满足 $ p_i | w $的边拿出来,并只保留这些边。则 $ l′ $ 等价于在这样得到的森林中,经过 $ (u, v) $ 的最长路径。

使用简单的树形DP即可求出某个点向子树方向以及向祖先方向延伸的最长路径,分类讨论即可对于每个 $ (u, v) $ 求出对应的 $ l′ $ 。

接下来考虑无解的情况。事实上,无解等价于刚刚求出的某个 $ l′ $ 和经过 $ (u, v) $ 的最长路径相同。经过 $ (u, v) $ 的最长路径和刚刚是同样的问题,直接对整棵树都做一遍树形 DP 即可。

接下来考虑复杂度。求出每个询问的 $ gcd $ 的复杂度为 $ O(q \log_2 n \log_2 w) $ ,而求出最长路的部分是与边数成线性的,而每条边至多出现 $ 7 $ 次,因此该做法的总复杂度即为 $ O(q \log_2 n \log_2 w + nω(w)) $ 。

CODE:

//9.10补全
#pragma GCC optimize(2)
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath> using namespace std; #define LL long long const int N = 2e5 + 100;
const int V = 2e6 + 100;
const int M = 18; struct Edge {
int to,from;
int data;
}e[N<<1]; int head[N],cnt,tot,n,q;
int f[M + 1][N],g[M + 1][N];
int prime[V],d[V],deep[N];
bool p[V]; inline void prework() {
d[1] = 1;
for(int i = 2 ; i <= V - 1 ; i++) {
if(!p[i]) prime[++tot] = i,d[i] = i;
for(int j = 1 ; j <= tot && i * prime[j] < V ; ++j) {
p[i * prime[j]] = true;
d[i * prime[j]] = prime[j];
if(!(i % prime[j])) break;
}
}
}
inline void add_edge(int x,int y,int z) {
e[++cnt].from = y;
e[cnt].data = z;
e[cnt].to = head[x];
head[x] = cnt;
}
inline int gcd(int a,int b) {
return !b ? a :gcd(b,a % b);
}
inline void dfs(int v,int fa) {
for(int i = 1 ; i <= M ; i++) {
f[i][v] = f[i - 1][f[i - 1][v]];
g[i][v] = gcd(g[i - 1][v],g[i - 1][f[i - 1][v]]);
}
for(int i = head[v] ; i ; i = e[i].to) {
if(e[i].from == fa) continue;
f[0][e[i].from] = v;
g[0][e[i].from] = e[i].data;
deep[e[i].from] = deep[v] + 1;
dfs(e[i].from,v);
}
}
inline int LCA(int x,int y) {
if(deep[x] != deep[y]) {
if(deep[x] < deep[y]) swap(x,y);
int dis = deep[x] - deep[y];
for(int i = 0 ; i <= M ; i++) {
if((1 << i) & dis) x = f[i][x];
}
}
if(x == y) return x;
for(int i = M ; i >= 0 ; i--) {
if(f[i][x] == f[i][y]) continue;
x = f[i][x],y = f[i][y];
}
return f[0][x];
}
inline int cal(int x,int y) {
if(deep[x] < deep[y]) swap(x,y);
int d = deep[x] - deep[y],ans = 0;
for(int i = 0 ; i <= M ; i++) {
if((1<<i)&d) {
ans = gcd(g[i][x],ans);
x = f[i][x];
}
}
return ans;
}
inline int calc(int x,int y) {
int l = LCA(x,y);
return gcd(cal(l,x),cal(l,y));
}
inline int dp(int v,int fa,int d) {
int ans = 0;
for(int i = head[v] ; i ; i = e[i].to) {
if(e[i].from == fa) continue;
if(e[i].data % d) continue;
ans = max(ans,dp(e[i].from,v,d)+1);
}
return ans;
}
inline int kth(int v,int k) {
for(int i = 0 ; i <= M ; i++) {
if((1 << i) & k) v = f[i][v];
}
return v;
}
inline int dis(int x,int y) {
return deep[x] + deep[y] - deep[LCA(x,y)] * 2;
}
inline int read() {
int x = 0, f = 1;
char ch = getchar();
while(ch < '0' || ch > '9') {if (ch == '-')f = -1; ch = getchar();}
while(ch >= '0' && ch <= '9') {x = (x << 1) + (x << 3) + (ch ^ 48); ch = getchar();}
return x * f;
} int main() {
prework();
n = read(),q = read();
for(int i = 1 ; i < n ; i++) {
int u = read(),v = read(),z = read();
add_edge(u,v,z);
add_edge(v,u,z);
}
dfs(1,0);
while(q--) {
int x = read(),y = read();
int l = LCA(x,y),g = calc(x,y);
if(g == 1) {
printf("%d \n",dis(x,y));
continue;
}
int fx = f[0][x],fy = f[0][y];
if(l == x) fx = kth(y,deep[y] - deep[x] - 1);
else if(l == y) fy = kth(x,deep[x] - deep[y] - 1); // 限制不走相同的子树
int mxdis = dp(x,fx,1) + dp(y,fy,1);
int ans = 0;
while(g != 1) {
int p = d[g];
ans = max(ans,dp(x,fx,p) + dp(y,fy,p));
if(ans == mxdis) break;
while(!(g % p)) g /= p;
}
printf("%d\n",ans == mxdis ? -1 : ans + dis(x,y) + 1);
}
//system("pause");
return 0;
}

ZR#959的更多相关文章

  1. CF 959 E. Mahmoud and Ehab and the xor-MST

    E. Mahmoud and Ehab and the xor-MST https://codeforces.com/contest/959/problem/E 分析: 每个点x应该和x ^ lowb ...

  2. IMP-00003: 遇到 ORACLE 错误 959 ORA-00959: 表空间 '' 不存在

    描述 在使用imp命令将dmp文件导入oracle中时,遇到如下错误: IMP: 遇到 ORACLE 错误 ORA: 表空间 'TBS_CDUSER' 不存在 IMP命令如下: IMP cduser/ ...

  3. ZR#1005

    ZR#1005 解法: 题解给了一个建图跑最短路的做法,但好像没有必要,因为 $ m $ 没有用,所以直接上完全背包就行了. CODE: #include<iostream> #inclu ...

  4. ZR#1004

    ZR#1004 解法: 对于 $ (x^2 + y)^2 \equiv (x^2 - y)^2 + 1 \pmod p $ 化简并整理得 $ 4x^2y \equiv 1 \pmod p $ 即 $ ...

  5. ZR#1009

    ZR#1009 解法: 因为无敌的SR给了一个大暴力算法,所以通过打表发现了了一些神奇的性质,即第一行和第一列的对应位置数值相等. 我们可以通过手算得出 $ F(n) = \frac{n(n + 1) ...

  6. ZR#1008

    ZR#1008 解法: 直接预处理出来执行完一个完整的串可以到达的位置,然后算出重复的次数直接乘在坐标上,最后处理一下余下的部分就行了. CODE: #include<iostream> ...

  7. ZR#1015

    ZR#1015 解法: 我们需要求得, $ g_i $ 表示长度为的最长不下降子序列个数. 设 $ f_{i,j} $ 表示统计第前$ i $ 个数字,得到最长不下降子序列末端为 $ j $ . 显然 ...

  8. ZR#1012

    ## ZR#1012 blog咕咕咕了好久,开始补. 解法: 一个很显然的性质, $ x $ 只能转移到 $ x+1 $ 或者 $ 2x $ 处,所以我们可以以此性质建图,即 $ x $ 向 $ x ...

  9. ZR#985

    ZR#985 解法: 可以先假设每个区间中所有颜色都出现,然后减掉多算的答案.对每种颜色记录它出现的位置,则相邻两个位置间的所有区间都要减去,时间复杂度 $ O(n) $ . 其实可以理解为加法原理的 ...

随机推荐

  1. SQL Sever 刪除重複數據只剩一條

    use book go create table ##T1( n int, a nvarchar(20) ) --查詢重複記錄,插入臨時表 insert into ##T1(n,a) select s ...

  2. .NET Standards

    .net的创始者们在一开始的时候,就意识到了他们的编程技术可以用在不通的操作系统和不同类型的cpu上.他们改进了20世纪90年代编程语言实现技术.最主要的一条是,不同的编程语言对应统一个运行时,及CL ...

  3. Dijkstra算法正确性证明

    问题:求图中点1到其他各点的最短距离 策略: 1.把起点1放入初始集合Set中,从剩余的点中,选取到Set(此时Set中只有1个点)距离最近的点,并入集合Set中, 2.从剩余的点中,找经过集合Set ...

  4. phpcms企业站的一些知识

    头header.html 尾footer.html 主页用index.html 列表页用list.html 单网页用page.html 内容页用show.html {template "co ...

  5. 多核cpu关闭、开启核心

    列表 # ls /sys/devices/system/cpu/ 关闭 # echo '0' > /sys/devices/system/cpu/cpu1/online 开启 # echo '1 ...

  6. 使用Idea初始化一个spring boot 项目

    配置环境 Idea配置jdk8.0 1.打开Idea,点击右上角file,找到Other Settings选项,点击下方的Default Project Structure,如下所示 2.点击下图中所 ...

  7. shell 三剑客之 sed 命令详解

    sed 编辑命令 sed 编辑命令对照表 把 /etc/passwd 文件赋值到当前路径下,进行操作 cp /etc/passwd ./ cat -n passwd sed 删除操作 删除 passw ...

  8. 【kernel】Centos 云上升级内核失败 如何处理【笔记记录转】

    Centos7选定默认启动的内核版本 vim /etc/grub2.cfg   修改timeout =5   修改成30天 版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附 ...

  9. 软件测试_Loadrunner_性能测试_脚本录制_录制多server请求脚本

    之前我们写过使用Loadrunner录制APP脚本的基本流程:软件测试_Loadrunner_APP测试_性能测试_脚本录制_基本操作流程,但是只能用于请求单一服务器端口适用 这次主要是写的多serv ...

  10. 开源框架---tensorflow c++ API中./configure步骤细节

    u@u160406:~/tf1.13/tensorflow$ git checkout r1.13 分支 r1.13 设置为跟踪来自 origin 的远程分支 r1.13.切换到一个新分支 'r1.1 ...