$g$是积性函数,可以通过分解质因数在$O(n\log n \log\log n)$的时间内求出。

对于$((A\times B)\times C)\times D$,可以转化为$D\times (C\times (B\times A))$,并视向量个数的奇偶性取反答案。

对于$D\times (C\times (B\times A))$,可以将$D\times$,$C\times$,$B\times$用$3$个$3\times 3$的矩阵表示,然后对树进行点分治即可。

时间复杂度$O(n\log n \log\log n)$。

#include<cstdio>
const int N=100010,E=N*20,M=1000010,P=1000000007;
int n,m,i,j,x,y,a[N],mv;
int g[N],v[N<<1],nxt[N<<1],ok[N<<1],ed;
int all,f[N],son[N],now,pos[N];
int G[N],V[E],NXT[E],ED,p[N],d[N],cnt,ans[N][3];
struct Q{int x,y;}q[N];
inline void read(int&a){char c;while(!(((c=getchar())>='0')&&(c<='9')));a=c-'0';while(((c=getchar())>='0')&&(c<='9'))(a*=10)+=c-'0';}
inline void add(int x,int y){v[++ed]=y;nxt[ed]=g[x];ok[ed]=1;g[x]=ed;}
inline void ADD(int x,int y){V[++ED]=y;NXT[ED]=G[x];G[x]=ED;}
namespace Num{
int inv[M],p[N],tot,mul,m[M],pm[M],g[M];bool v[M];
void init(){
for(i=2;i<=mv;i++){
if(!v[i])p[tot++]=i;
for(j=0;j<tot;j++){
if(i*p[j]>mv)break;
v[i*p[j]]=1;
if(i%p[j]==0)break;
}
}
for(inv[0]=inv[1]=1,i=2;i<=mv;i++)inv[i]=1LL*(P-inv[P%i])*(P/i)%P;
for(mul=1,i=2;i<=mv;i++)pm[i]=g[i]=1;
}
int exgcd(int a,int b){
if(!b)return x=1,y=0,a;
int d=exgcd(b,a%b),t=x;
return x=y,y=t-a/b*y,d;
}
inline int rev(int a){exgcd(a,P);while(x<0)x+=P;return x%P;}
inline void up(int&a,int b){a+=b;if(a>=P)a-=P;}
inline void add(int x){
m[x]++;
g[x]=(1LL*(x-1)*pm[x]%P*m[x]+g[x])%P;
pm[x]=1LL*pm[x]*x%P;
up(g[x],pm[x]);
}
inline void del(int x){
up(g[x],P-pm[x]);
pm[x]=1LL*pm[x]*inv[x]%P;
g[x]=(1LL*(P-x+1)*pm[x]%P*m[x]+g[x])%P;
m[x]--;
}
inline void divadd(int n){
for(int i=0;p[i]*p[i]<=n;i++)if(n%p[i]==0){
int j=p[i],old=rev(g[j]);
while(n%j==0)n/=j,add(j);
mul=1LL*mul*old%P*g[j]%P;
}
if(n==1)return;
int old=rev(g[n]);
add(n);
mul=1LL*mul*old%P*g[n]%P;
}
inline void divdel(int n){
for(int i=0;p[i]*p[i]<=n;i++)if(n%p[i]==0){
int j=p[i],old=rev(g[j]);
while(n%j==0)n/=j,del(j);
mul=1LL*mul*old%P*g[j]%P;
}
if(n==1)return;
int old=rev(g[n]);
del(n);
mul=1LL*mul*old%P*g[n]%P;
}
}
int mat[N][3][3],vec[N][3],A[N][3][3],B[N][3][3],C[3][3];
inline void mul(int a[][3],int b[][3],int c[][3]){
c[0][0]=(1LL*a[0][0]*b[0][0]+1LL*a[0][1]*b[1][0]+1LL*a[0][2]*b[2][0])%P;
c[0][1]=(1LL*a[0][0]*b[0][1]+1LL*a[0][1]*b[1][1]+1LL*a[0][2]*b[2][1])%P;
c[0][2]=(1LL*a[0][0]*b[0][2]+1LL*a[0][1]*b[1][2]+1LL*a[0][2]*b[2][2])%P;
c[1][0]=(1LL*a[1][0]*b[0][0]+1LL*a[1][1]*b[1][0]+1LL*a[1][2]*b[2][0])%P;
c[1][1]=(1LL*a[1][0]*b[0][1]+1LL*a[1][1]*b[1][1]+1LL*a[1][2]*b[2][1])%P;
c[1][2]=(1LL*a[1][0]*b[0][2]+1LL*a[1][1]*b[1][2]+1LL*a[1][2]*b[2][2])%P;
c[2][0]=(1LL*a[2][0]*b[0][0]+1LL*a[2][1]*b[1][0]+1LL*a[2][2]*b[2][0])%P;
c[2][1]=(1LL*a[2][0]*b[0][1]+1LL*a[2][1]*b[1][1]+1LL*a[2][2]*b[2][1])%P;
c[2][2]=(1LL*a[2][0]*b[0][2]+1LL*a[2][1]*b[1][2]+1LL*a[2][2]*b[2][2])%P;
}
void dfs(int x,int y){
Num::divadd(a[x]);
vec[x][0]=Num::mul;
vec[x][1]=x<<2;
vec[x][2]=1;
for(int i=g[x];i;i=nxt[i])if(v[i]!=y)dfs(v[i],x),vec[x][2]+=vec[v[i]][2];
mat[x][0][1]=P-vec[x][2];
mat[x][0][2]=vec[x][1];
mat[x][1][0]=vec[x][2];
mat[x][1][2]=P-vec[x][0];
mat[x][2][0]=P-vec[x][1];
mat[x][2][1]=vec[x][0];
Num::divdel(a[x]);
}
void findroot(int x,int y){
son[x]=1;f[x]=0;
for(int i=g[x];i;i=nxt[i])if(ok[i]&&v[i]!=y){
findroot(v[i],x);
son[x]+=son[v[i]];
if(son[v[i]]>f[x])f[x]=son[v[i]];
}
if(all-son[x]>f[x])f[x]=all-son[x];
if(f[x]<f[now])now=x;
}
void dfs1(int x,int y,int z){
pos[x]=z;f[x]=y;d[x]=d[y]^1;
mul(mat[x],A[y],A[x]);
for(int i=g[x];i;i=nxt[i])if(ok[i]&&v[i]!=y)dfs1(v[i],x,z);
}
void dfs2(int x,int y){
mul(B[y],mat[x],B[x]);
for(int i=g[x];i;i=nxt[i])if(ok[i]&&v[i]!=y)dfs2(v[i],x);
}
void solve(int x){
if(!G[x])return;
f[0]=all=son[x],findroot(x,now=0);
int i;
pos[now]=now;
for(int i=0;i<3;i++)for(int j=0;j<3;j++)A[now][i][j]=0;
A[now][0][0]=A[now][1][1]=A[now][2][2]=1;
mul(A[now],mat[now],B[now]);
f[now]=d[now]=0;
for(i=g[now];i;i=nxt[i])if(ok[i])dfs1(v[i],now,v[i]),dfs2(v[i],now);
for(cnt=0,i=G[x];i;i=NXT[i])p[++cnt]=V[i];G[x]=0;
for(i=1;i<=cnt;i++)if(pos[q[p[i]].x]==pos[q[p[i]].y])ADD(pos[q[p[i]].x],p[i]);
else{
int X=q[p[i]].x,Y=q[p[i]].y;
mul(A[Y],B[f[X]],C);
ans[p[i]][0]=(1LL*C[0][0]*vec[X][0]+1LL*C[0][1]*vec[X][1]+1LL*C[0][2]*vec[X][2])%P;
ans[p[i]][1]=(1LL*C[1][0]*vec[X][0]+1LL*C[1][1]*vec[X][1]+1LL*C[1][2]*vec[X][2])%P;
ans[p[i]][2]=(1LL*C[2][0]*vec[X][0]+1LL*C[2][1]*vec[X][1]+1LL*C[2][2]*vec[X][2])%P;
if(d[X]^d[Y]){
ans[p[i]][0]=P-ans[p[i]][0];
ans[p[i]][1]=P-ans[p[i]][1];
ans[p[i]][2]=P-ans[p[i]][2];
}
}
for(i=g[now];i;i=nxt[i])if(ok[i])ok[i^1]=0,solve(v[i]);
}
int main(){
B[0][0][0]=B[0][1][1]=B[0][2][2]=1;
read(n),read(m);
for(ed=i=1;i<=n;i++){
read(a[i]);
if(a[i]>mv)mv=a[i];
}
for(i=1;i<n;i++)read(x),read(y),add(x,y),add(y,x);
Num::init();
dfs(1,0);
for(i=1;i<=m;i++){
read(q[i].x),read(q[i].y);
if(q[i].x==q[i].y){
ans[i][0]=vec[q[i].x][0];
ans[i][1]=vec[q[i].x][1];
ans[i][2]=vec[q[i].x][2];
}else ADD(1,i);
}
son[1]=n;solve(1);
for(i=1;i<=m;i++)printf("%d %d %d\n",ans[i][0],ans[i][1],ans[i][2]);
return 0;
}

  

BZOJ4623 : Styx的更多相关文章

  1. uva 1599 ideal path(好题)——yhx

    aaarticlea/png;base64,iVBORw0KGgoAAAANSUhEUgAABGYAAAODCAYAAAD+ZwdMAAAgAElEQVR4nOy9L8/0ypH/Pa8givGiyC

  2. 分布式系统(Distributed System)资料

    这个资料关于分布式系统资料,作者写的太好了.拿过来以备用 网址:https://github.com/ty4z2008/Qix/blob/master/ds.md 希望转载的朋友,你可以不用联系我.但 ...

  3. 想从事分布式系统,计算,hadoop等方面,需要哪些基础,推荐哪些书籍?--转自知乎

    作者:廖君链接:https://www.zhihu.com/question/19868791/answer/88873783来源:知乎 分布式系统(Distributed System)资料 < ...

  4. 杭电1010Tempter of the Bone

    Tempter of the Bone Problem Description The doggie found a bone in an ancient maze, which fascinated ...

  5. 有关ListBox

    如何拿到Source:从SQL,从XML file SQL:一个是ObjectDataProvider //用linq方法拿到SQL data,wrap到一个IEnumerable<Custom ...

  6. python瓦登尔湖词频统计

    #瓦登尔湖词频统计: import string path = 'D:/python3/Walden.txt' with open(path,'r',encoding= 'utf-8') as tex ...

  7. Ubuntu下Git的使用之创建版本库

    创建版本库 什么是版本库呢?版本库又名仓库,英文名repository,你可以简单理解成一个目录,这个目录里面的所有文件都可以被Git管理起来,每个文件的修改.删除,Git都能跟踪,以便任何时刻都可以 ...

  8. Synchronize Ultimate

    支持多种服务器和主流云网盘进行同步 http://www.icecoldapps.com/ Unlock Code : xda201506 Unlock Code : icecoldapps20150 ...

  9. hduoj---Tempter of the Bone

    Tempter of the Bone Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Othe ...

随机推荐

  1. JS ——window.onload与$(document).ready()

    我们常常在页面加载完成以后做一些操作,比如一些元素的显示与隐藏.一些动画效果.我们通常有两种方法来完成这个事情,一个就是window.onload事件,另一个就是JQuery的ready()方法.那么 ...

  2. AXURE在原型设计中的应用

    转: http://uedc.163.com/2248.html 前言 什么是原型呢? 产品原型简单的说就是产品设计成形之前的一个简单框架,对网站来讲,就是将页面模块.元素进行粗放式的排版和布局,深入 ...

  3. JAVA基础学习之final关键字、遍历集合、日期类对象的使用、Math类对象的使用、Runtime类对象的使用、时间对象Date(两个日期相减)(5)

    1.final关键字和.net中的const关键字一样,是常量的修饰符,但是final还可以修饰类.方法.写法规范:常量所有字母都大写,多个单词中间用 "_"连接. 2.遍历集合A ...

  4. HTML页面实现返回顶部效果 go to top

    1.首先导入jQuery插件. 2.js代码: $(window).scroll(function () { if($(window).scrollTop()>=100) { $(". ...

  5. jQuery easyUI datagrid 增加求和统计行 分类: JavaScript 2015-01-14 17:46 2178人阅读 评论(0) 收藏

    在datagrid的onLoadSuccess事件增加代码处理. <style type="text/css"> .subtotal { font-weight: bo ...

  6. BAT批量处理 命令

    第一章 批处理基础第一节 常用批处理内部命令简介 批处理定义:顾名思义,批处理文件是将一系列命令按一定的顺序集合为一个可执行的文本文件,其扩展名为BAT或者CMD.这些命令统称批处理命令.小知识:可以 ...

  7. wp8 入门到精通 数据库更新字段(一)

    public class UserInfoDB : BaseDB { public UserInfoDB() : base(@"Data Source=isostore:\MakeLove\ ...

  8. hdu 4050 2011北京赛区网络赛K 概率dp ***

    题目:给出1-n连续的方格,从0开始,每一个格子有4个状态,左右脚交替,向右跳,而且每一步的步长必须在给定的区间之内.当跳出n个格子或者没有格子可以跳的时候就结束了,求出游戏的期望步数 0:表示不能到 ...

  9. Android系统介绍与框架(转)

    一.Andriod是什么? Android系统是Google开发的一款开源移动OS,Android中文名被国内用户俗称“安卓”.Android操作系统基于Linux内核设计,使用了Google公司自己 ...

  10. win10无法枚举容器中的对象 访问被拒绝

    http://jingyan.baidu.com/article/48a42057cd0bc0a924250419.html