【题解】CF986E Prince's Problem(树上差分+数论性质)
【题解】CF986E Prince's Problem(树上差分+数论性质)
题目大意:
给定你一棵树,有点权\(val_i\le 10^7\)。现在有\(m\)组询问给定参数\(x,y,w\)问你对于\((x->y)\)的路径经过的点集\(P\),问你这个东西:
\[\prod_{u \in P} {\mathrm{gcd}(w,val_u)} \mod 1000000007
\]
考虑这样一种做法:
把询问差分成
\[\]\[\]考虑这类从根出发如何解决,直接遍历整棵树,对于每个节点先将自己的贡献加入某种数据结构,再递归子树,最后回溯时撤回贡献。问题就变为如何快速求\(\prod \mathrm{gcd}\)
考虑\(gcd\)的本质就是对于质因子取\(min\)且求和,而且我们知道\(1e7\)以内的质数是不多的(\(5e6\)左右),所以直接对于每个质数开一个\(vector\)。\(vector_i\)中的下标\(j\)表示唯一分解后\(\alpha(prime[i])=j\)的树上节点有多少个。(\(\alpha\)是唯一分解后的指数)。考虑到\(\sum \alpha\)很小是\(\log\)级别,这样复杂度就是\(O(1e7+(n+m)\log 1e7)\)空间复杂度\(O((n +q)\log 1e7)\)
主要就是树上差分,还有处理\(\sum \min\{...\}\)的方法。
//@winlere
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#define inv(x) (ksm((x)%mod,mod-2))
using namespace std; typedef long long ll;
inline int qr(){
register int ret=0,f=0;
register char c=getchar();
while(c<48||c>57)f|=c==45,c=getchar();
while(c>=48&&c<=57) ret=ret*10+c-48,c=getchar();
return f?-ret:ret;
}
const int mod=1e9+7;
int n,m;
inline int ksm(const int&ba,const int&p){
int ret=1;
for(int t=p,b=ba%mod;t;t>>=1,b=1ll*b*b%mod)
if(t&1) ret=1ll*ret*b%mod;
return ret;
}
vector< vector<int> > s;
namespace PRE{
const int maxn=1e7+5;
int rank[maxn],usd[maxn],arc[maxn],Min[maxn];
vector<int> pr;
inline void pre(const int&n){
usd[1]=1; Min[1]=10;
for(int t=2;t<=n;++t){
if(!usd[t]) Min[t]=t,pr.push_back(t),rank[t]=pr.size(),arc[rank[t]]=t;
for(auto f:pr){
if(1ll*f*t>n)break;
usd[f*t]=1;
Min[f*t]=f;
if(t%f==0)break;
}
}
s.resize(pr.size()+1);
}
}
namespace TREE{
const int maxn=1e5+5;
int d[maxn];
vector<int> e[maxn];
vector<int> q[maxn];
int W[maxn],ans[maxn],w[maxn];
inline void add(const int&fr,const int&to){
e[fr].push_back(to);
e[to].push_back(fr);
}
int son[maxn],top[maxn],r[maxn],siz[maxn];
void pre(const int&now,const int&last){
siz[now]=1;
r[now]=last;
d[now]=d[last]+1;
for(auto t:e[now])
if(t^last) {
pre(t,now); siz[now]+=siz[t];
if(siz[now]>siz[son[now]]) son[now]=t;
}
}
void qaq(const int&now,const int&last){
top[now]=last;
if(son[now]) qaq(son[now],last);
for(auto t:e[now])
if((t^r[now])&&(t^son[now]))
qaq(t,t);
}
inline void init(const int&n){pre(1,0);qaq(1,0);}
inline int lca(int u,int v){
if(d[u]<d[v])swap(u,v);
while(top[u]^top[v]){
if(d[top[u]]<d[top[v]]) swap(u,v);
u=r[top[u]];
}
return d[u]<d[v]?u:v;
}
inline void addq(const int&x,const int&y,const int&id,const int&w){
ans[id]=1;
q[x].push_back(id);
q[y].push_back(id);
q[lca(x,y)].push_back(-id);
W[id]=w;
}
}
namespace sol{
const int maxn=1e5+5;
using namespace TREE;
using PRE::rank;
using PRE::Min;
inline void add(const int&now,const int&tag){
//now 是节点编号 tag 是操作类型
int k=w[now],cnt=0;
static int a[23],p[23];
while(k>1){
int f=Min[k];
a[++cnt]=0;
p[cnt]=f;
while(k%f==0) k/=f,++a[cnt];
}
for(int t=1;t<=cnt;++t){
if(((int)s[rank[p[t]]].size())<=1+a[t])
s[rank[p[t]]].resize(a[t]+2);
s[rank[p[t]]][a[t]]+=tag;
}
}
inline void que(const int&now,const int&id){
//now 是询问编号
int k=W[now>0?now:-now],cnt=0,ret=1;
static int a[23],p[23];
while(k>1){
int f=Min[k];
a[++cnt]=0;
p[cnt]=f;
while(k%f==0) k/=f,++a[cnt];
}
for(int t=1;t<=cnt;++t)
for(int i=1,ed=s[rank[p[t]]].size();i<ed;++i)
ret=1ll*ret*ksm(p[t],1ll*s[rank[p[t]]][i]*min(a[t],i)%(mod-1))%mod;
if(now<0) ans[-now]=1ll*ans[-now]*inv(ret)%mod*inv(ret)%mod*__gcd(W[-now],w[id])%mod;
else ans[now]=1ll*ans[now]*ret%mod;
}
void dfs(const int&now,const int&last){
add(now,1);
for(auto t:q[now]) que(t,now);
for(auto t:e[now])
if(t^last) dfs(t,now);
add(now,-1);
}
}
int main(){
PRE::pre(1e7);
n=qr();
for(int t=2;t<=n;++t) TREE::add(qr(),qr());
for(int t=1;t<=n;++t) TREE::w[t]=qr();
TREE::init(n);
m=qr();
for(int t=1,t1,t2,t3;t<=m;++t) {
t1=qr(); t2=qr(); t3=qr();
TREE::addq(t1,t2,t,t3);
}
sol::dfs(1,0);
for(int t=1;t<=m;++t) printf("%d\n",TREE::ans[t]);
return 0;
}
【题解】CF986E Prince's Problem(树上差分+数论性质)的更多相关文章
- bzoj3307 雨天的尾巴 题解(线段树合并+树上差分)
Description N个点,形成一个树状结构.有M次发放,每次选择两个点x,y 对于x到y的路径上(含x,y)每个点发一袋Z类型的物品.完成 所有发放后,每个点存放最多的是哪种物品. Input ...
- 【BZOJ3307】雨天的尾巴 题解(树链剖分+树上差分)
题目链接 题目大意:给定一颗含有$n$个结点的树,每次选择两个结点$x$和$y$,对从$x$到$y$的路径上发放一带$z$类型的物品.问完成所有操作后每个结点发放最多的时哪种物品. 普通的树链剖分貌似 ...
- [CF986E]Prince's Problem
题意:给一棵带点权$w_i$的树,多次询问$(u,v,x)$,求出$\prod\limits_{i\in\text{path}(u,v)}(w_i,x)$ 因为是乘法,所以可以把路径询问拆成到根询问, ...
- BZOJ 4326: NOIP2015 运输计划(二分,树上差分)
Time Limit: 30 Sec Memory Limit: 128 MBSubmit: 1945 Solved: 1243[Submit][Status][Discuss] Descript ...
- 【题解】POJ 3417 Network(倍增求LCA+DP+树上差分)
POJ3417:http://poj.org/problem?id=3417 思路 我们注意到由“主要边”构成一颗树 “附加边”则是非树边 把一条附加边(x,y)加入树中 会与树上x,y之间构成一个环 ...
- BZOJ4999 This Problem Is Too Simple!(树上差分+dfs序+树状数组)
对每个权值分别考虑.则只有单点加路径求和的操作.树上差分转化为求到根的路径和,子树加即可.再差分后bit即可.注意树上差分中根的父亲是0,已经忘了是第几次因为这个挂了. #include<ios ...
- bzoj3307 雨天的尾巴题解及改题过程(线段树合并+lca+树上差分)
题目描述 N个点,形成一个树状结构.有M次发放,每次选择两个点x,y对于x到y的路径上(含x,y)每个点发一袋Z类型的物品.完成所有发放后,每个点存放最多的是哪种物品. 输入格式 第一行数字N,M接下 ...
- luoguP3128 [USACO15DEC]最大流Max Flow 题解(树上差分)
链接一下题目:luoguP3128 [USACO15DEC]最大流Max Flow(树上差分板子题) 如果没有学过树上差分,抠这里(其实很简单的,真的):树上差分总结 学了树上差分,这道题就极其显然了 ...
- luoguP3258 [JLOI2014]松鼠的新家 题解(树上差分)
P3258 [JLOI2014]松鼠的新家 题目 树上差分:树上差分总结 #include<iostream> #include<cstdlib> #include<c ...
随机推荐
- 胡喜:从 BASIC 到 basic ,蚂蚁金服技术要解决两个基本的计算问题
摘要: 揭开 BASIC College 神秘面纱,蚂蚁金服首次揭秘人才培养机制. 导读:5 月 6 日,蚂蚁金服副 CTO 胡喜在 2019 年 QCon 上做了<蚂蚁金服十五年技术架构演进之 ...
- 在springmvc中 @RequestMapping(value={"", "/"})是什么意思
这个意思是说请求路径 可以为空或者/ 我给你举个例子:比如百度知道的个人中心 访问路径是 http://zhidao.baidu.com/ihome,当然你也可以通过 http://zhidao.ba ...
- oracle函数 localtimestamp
[功能]:返回会话中的日期和时间 [参数]:没有参数,没有括号 [返回]:日期 [示例]select localtimestamp from dual; 返回:14-11月-08 12.35.37.4 ...
- 2018年NOIP普及组复赛题解
题目涉及算法: 标题统计:字符串入门题: 龙虎斗:数学题: 摆渡车:动态规划: 对称二叉树:搜索. 标题统计 题目链接:https://www.luogu.org/problem/P5015 这道题目 ...
- SVG和canvas画图,js求数组最大最小值
windows命令行的内容怎么复制,右键选择标记,选中内容后再点击鼠标右键就复制了. 安装Node.js后再用npm install命令会出现如下warn:saveError ENOENT: no s ...
- Array.from()类数组转化为数组的用法
类数组对象转化为数组 let arrayLike = { '0': 'a', '1': 'b', '2': 'c', length: 3 }; let arr = Array.from(arrayLi ...
- Flex AIR应用换肤功能(Android和IOS)
说明 换肤功能,即将整个应用的皮肤都进行更换,其实质,是动态加载swf文件的过程,而这些swf文件则有css文件编译而来. 关于换肤功能,在android和ios系统的实现方式是不同的.主要原因,是因 ...
- CF1166E The LCMs Must be Large
CF1166E The LCMs Must be Large 构造趣题 正着推其实很不好推 不妨大力猜结论 如果两两集合都有交,那么一定可以 证明: 1.显然如果两个集合没有交,一定不可以 2.否则给 ...
- java 操作流的步骤
File类本身是与文件操作有关,但是如果要想操作内容则必须使用字节流或字符流完成,但是不管是使用何种的输入输出流,其基本的操作原理是一样的(以文件流为准): 一.使用File类找到一个文件对象,得到I ...
- UVA 12563 "Jin Ge Jin Qu hao" (背包)
传送门 debug了好一会,突然发现,输出错了,emmm......... 明天再写debug历程: (PS:ipad debug是真的繁琐) 题意: 题解: 尽管题干中给的 t 的范围很大,但是 t ...