专栏文章

题解:P12001 在小小的奶龙山里面挖呀挖呀挖

P12001题解参与者 2已保存评论 1

文章操作

快速查看文章及其快照的属性,并进行相关操作。

当前评论
1 条
当前快照
1 份
快照标识符
@mipryj4v
此快照首次捕获于
2025/12/03 16:58
3 个月前
此快照最后确认于
2025/12/03 16:58
3 个月前
查看原文
比题解更无脑的做法。
请注意算法常数对时间效率的影响。
加上 5s5s 时限,说明如果常数够小可以通过。
发现 10510^5 以内的素数只有 10410^4 个,发现不能开 n×104n\times 10^4 的数组,那么将询问离线下来,对于每个素数考虑,树上差分维护。假设当前处理素数 pp,记 ctxct_x 表示 1x1\sim x 路径上的点有多少个 aia_i 满足 pp 整除 aia_i。这个显然可以 dfs O(n)O(n) 更新。
但是 dfs 更新太慢了,考虑卡常经典操作,将树拍成 dfs 序更新即可,求 LCA 用的 ST 表,最大点不超过一坤秒。
CPP
#include<bits/stdc++.h>
using namespace std;
#define rep(i,s,t,p) for(int i = s;i <= t;i += p)
#define drep(i,s,t,p) for(int i = s;i >= t;i -= p)
#ifdef LOCAL
  auto I = freopen("in.in","r",stdin),O = freopen("out.out","w",stdout);
#else
  auto I = stdin,O = stdout;
#endif
using ll = long long;using ull = unsigned long long;
using db = double;using ldb = long double;
const int N = 5e4 + 10;
#define eb emplace_back
vector<int> e[N],prime;
bitset<100010> vis;
int ct[N],n,m,a[N],u[N],v[N],dfn[N],tim,st[18][N],ans[N],lca[N],F[N],rdfn[N];
void shai(int n){
	for(int i = 2;i <= 100000; ++i){
		if(!vis[i]) prime.emplace_back(i);
		for(auto j:prime){
			if(i * j > n) break;
			vis[i * j] = true;
			if(i % j == 0) break;
		}
	}
}
void dfs(int x,int fa){
	st[0][dfn[x] = ++tim] = fa;F[x] = fa;
	rdfn[tim] = x;
	for(auto y:e[x]) if(y ^ fa) dfs(y,x);
}
int get(int x,int y){return dfn[x] < dfn[y]?x:y;}
int LCA(int x,int y){
	if(x == y) return x;
	if((x = dfn[x]) > (y = dfn[y])) swap(x,y);
	int k = __lg(y-x++);
	return get(st[k][x],st[k][y-(1<<k)+1]);
}
void pdfs(const int &now){
	for(int i = 1;i <= n; ++i){
		int x = rdfn[i];
		ct[x] = ct[F[x]];
		ct[x] += a[x]%now == 0;
	}
}
signed main(){
  cin.tie(nullptr)->sync_with_stdio(false);
	shai(100000);
	cin>>n>>m;
	for(int i = 1;i <= n; ++i) cin>>a[i];
	for(int i = 1,u,v;i < n; ++i) cin>>u>>v,e[u].eb(v),e[v].eb(u);
	dfs(1,0);
	for(int j = 1;j <= __lg(n); ++j)
		for(int i = 1;i + (1 << j) - 1 <= n; ++i)
			st[j][i] = get(st[j-1][i],st[j-1][i+(1<<(j-1))]);
	for(int i = 1;i <= m; ++i){
		cin>>u[i]>>v[i],lca[i] = LCA(u[i],v[i]);
	}
	for(auto now:prime){
		pdfs(now);
		for(int i = 1;i <= m; ++i){
			if(ct[u[i]] + ct[v[i]] - ct[lca[i]] - ct[F[lca[i]]]){
				ans[i]++;
			}
		}
	}
	for(int i = 1;i <= m; ++i) cout<<ans[i]<<'\n';
}

评论

1 条评论,欢迎与作者交流。

正在加载评论...