路径计数
System Message (命题人)
基准时间限制:1 秒 空间限制:131072 KB 分值: 80
路径上所有边权的最大公约数定义为一条路径的值。
给定一个有向无环图。
T次修改操作,每次修改一条边的边权,每次修改后输出有向无环图上路径的值为1的路径数量(对1,000,000,007取模)。
Input
第一行两个整数n和m,分别表示有向无环图上的点数和边数。(1<=n<=100,1<=m<=50,000)
第2~m+1行每行三个数x,y,z,表示有一条从x到y权值为z的边。(1<=x,y<=n,1<=z<=100)
第m+2行一个数T,表示修改操作次数(1<=T<=500)。
接下来T行每行两个数x,y,表示修改第x条边(按照读入的顺序)的边权为y(1<=x<=m,1<=y<=100)。
Output
T+1行,修改前和每次修改操作后输出答案。
Input示例
4 4
1 2 2
2 4 3
1 3 4
3 4 2
4
1 5
2 10
3 3
4 6
Output示例
1
1
0
1
0
这题是个有向图,然后求路径gcd=1的条数,因为gcd一共就1−100,点100个
所以枚举gcd,枚举当前点,枚举连接的点,是O(100∗n2)
因为有500组修改,所以过不去GG
于是想到,每次修改一条边的权值,只会对权值的gcd的路径个数产生影响,如果原来是3,那么对gcd=2的完全没影响
想到这里就可以修改状态了,mat[k][i][j]表示,权值为k的倍数的i,j之间的路径个数
这样就能求出,权值为i的倍数的路径条数
说到这里,直接容斥就能求出权值为i的路径条数
然后修改的话,每次只要修改权值的因子的值就行
把O(T∗v∗n2)优化到了O(T∗sqrt(v)∗n2)
代码:
#include <map>
#include <set>
#include <stack>
#include <queue>
#include <cmath>
#include <string>
#include <vector>
#include <cstdio>
#include <cctype>
#include <cstring>
#include <sstream>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#pragma comment(linker,"/STACK:102400000,102400000")
using namespace std;
#define MAX 100005
#define MAXN 1000005
#define maxnode 205
#define sigma_size 2
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define lrt rt<<1
#define rrt rt<<1|1
#define middle int m=(r+l)>>1
#define LL long long
#define ull unsigned long long
#define mem(x,v) memset(x,v,sizeof(x))
#define lowbit(x) (x&-x)
#define pii pair<int,int>
#define bits(a) __builtin_popcount(a)
#define mk make_pair
#define limit 10000
//const int prime = 999983;
const int INF = 0x3f3f3f3f;
const LL INFF = 0x3f3f;
//const double pi = acos(-1.0);
const double inf = 1e18;
//const double eps = 1e-9;
const LL mod = 1e9+7;
const ull mx = 133333331;
/*****************************************************/
inline void RI(int &x) {
char c;
while((c=getchar())<'0' || c>'9');
x=c-'0';
while((c=getchar())>='0' && c<='9') x=(x<<3)+(x<<1)+c-'0';
}
/*****************************************************/
LL dp[105];
int a[50005],b[50005],c[50005];
int mat[105][105][105];
LL g[105];
LL f[105];
int n;
LL dfs(int u,int d){
if(dp[u]!=-1) return dp[u];
LL ans=0;
for(int i=1;i<=n;i++){
if(mat[d][u][i]){
ans=(ans+mat[d][u][i]+mat[d][u][i]*dfs(i,d))%mod;
}
}
return dp[u]=ans;
}
LL cal(int u){
mem(dp,-1);
for(int i=1;i<=n;i++){
if(dp[i]==-1) dfs(i,u);
}
LL ans=0;
for(int i=1;i<=n;i++) ans=(ans+dp[i])%mod;
return ans;
}
int main(){
//freopen("in.txt","r",stdin);
int m;
cin>>n>>m;
mem(mat,0);
for(int i=1;i<=m;i++){
scanf("%d%d%d",&a[i],&b[i],&c[i]);
for(int j=1;j*j<=c[i];j++){
if(c[i]%j==0){
mat[j][a[i]][b[i]]++;
if(c[i]/j!=j) mat[c[i]/j][a[i]][b[i]]++;
}
}
}
for(int i=1;i<=100;i++) g[i]=cal(i);
for(int i=100;i>0;i--){
f[i]=g[i];
for(int j=2*i;j<=100;j+=i){
f[i]-=f[j];
}
f[i]=(f[i]%mod+mod)%mod;
}
cout<<f[1]<<endl;
int t;
cin>>t;
while(t--){
int x,y;
scanf("%d%d",&x,&y);
vector<int> v;
for(int i=1;i*i<=c[x];i++){
if(c[x]%i==0){
mat[i][a[x]][b[x]]--;
v.push_back(i);
if(c[x]/i!=i) mat[c[x]/i][a[x]][b[x]]--,v.push_back(c[x]/i);
}
}
c[x]=y;
for(int i=1;i*i<=c[x];i++){
if(c[x]%i==0){
mat[i][a[x]][b[x]]++;
v.push_back(i);
if(c[x]/i!=i) mat[c[x]/i][a[x]][b[x]]++,v.push_back(c[x]/i);
}
}
for(int i=0;i<v.size();i++){
g[v[i]]=cal(v[i]);
}
for(int i=100;i>0;i--){
f[i]=g[i];
for(int j=2*i;j<=100;j+=i){
f[i]-=f[j];
}
f[i]=(f[i]%mod+mod)%mod;
}
cout<<f[1]<<endl;
}
return 0;
}