题意:n点m条边的有向无环图,定义一条路径的价值为:该路径上所有边权的最大公约数.
n,w<=100,Q<=500,m<=5e4.Q次操作:修改一条边的权值,并询问价值为1的路径数量?
因为边权最大为100.可以拆成100个子图.第x个子图的路径值只能为x的倍数.
设g[i]为第i个子图的路径个数.容易容斥算出f[i],价值为i的路径总个数
因为为DAG,dp[u][x]以u为起点的价值为x倍数的路径个数.记忆化搜索求出g的值.O(n^3).
修改一条边的权值w,相当于更新所有d|w的子图 求一个子图的路径个数O(n^2)
n,w<=100,Q<=500,m<=5e4.Q次操作:修改一条边的权值,并询问价值为1的路径数量?
因为边权最大为100.可以拆成100个子图.第x个子图的路径值只能为x的倍数.
设g[i]为第i个子图的路径个数.容易容斥算出f[i],价值为i的路径总个数
因为为DAG,dp[u][x]以u为起点的价值为x倍数的路径个数.记忆化搜索求出g的值.O(n^3).
修改一条边的权值w,相当于更新所有d|w的子图 求一个子图的路径个数O(n^2)
总的复杂度为O(Q*n^2*max(w的约数个数)
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e2+5,M=5e4,mod=1e9+7;
ll n,m,id,w,Q,a[M],b[M],c[M],edg[N][N][N],g[N],f[N],dp[N];
ll dfs(int u,int x){
if(dp[u]!=-1) return dp[u];
ll res=0;
for(int j=1;j<=n;j++)
if(edg[x][u][j]) res=(res+edg[x][u][j]*(1+dfs(j,x)))%mod;
return dp[u]=res;
}
ll calc(int x){
memset(dp,-1,sizeof(dp));
ll res=0;
for(int i=1;i<=n;i++) res=(res+dfs(i,x))%mod;
return res;
}
void update(int u,int v,int w,int val){
for(int j=1;j*j<=w;j++){
if(w%j) continue;
edg[j][u][v]+=val;
if(j*j!=w) edg[w/j][u][v]+=val;
}
}
void print(){
for(int i=100;i>=1;i--){
f[i]=g[i];
for(int j=2*i;j<=100;j+=i)
f[i]=(f[i]-f[j]+mod)%mod;
}
cout<<f[1]<<'\n';
}
int main()
{
ios::sync_with_stdio(false);cin.tie(0);
memset(edg,0,sizeof(edg));
cin>>n>>m;
for(int i=1;i<=m;i++){
cin>>a[i]>>b[i]>>c[i];
update(a[i],b[i],c[i],1);
}
for(int x=1;x<=100;x++) g[x]=calc(x);//O(n^3)
print();
cin>>Q;
while(Q--){
cin>>id>>w;
vector<int> vec;
for(int j=1;j*j<=c[id];j++){
if(c[id]%j) continue;
vec.push_back(j),edg[j][a[id]][b[id]]--;
if(j*j!=c[id]) vec.push_back(c[id]/j),edg[c[id]/j][a[id]][b[id]]--;
}
c[id]=w;
for(int j=1;j*j<=c[id];j++){
if(c[id]%j) continue;
vec.push_back(j),edg[j][a[id]][b[id]]++;
if(j*j!=c[id]) vec.push_back(c[id]/j),edg[c[id]/j][a[id]][b[id]]++;
}
for(int i=0;i<vec.size();i++) g[vec[i]]=calc(vec[i]);
//O(Q*(n^2*C)
print();
}
return 0;
}