原题连接:
https://www.51nod.com/onlineJudge/questionCode.html#!problemId=1610
记
f(n)
为路径值为
n
的路径数量。
记,F(n) 为路径值为
n
的倍数的路径数量,即:F(n)=∑n|df(d)
ans=f(1)=∑d≥1μ(d)F(d)
考虑不同权重为
d
的倍数的边组成的图.
F(d) 为此图中。路径总数量。
由于 m≤50000 .明显会出现重边。
建议限制边的数量或者使用邻接矩阵存图。
矩阵更为方便。
由于最初没有考边过多。使用了链表+拓扑排序。代码量较大。
#include <algorithm>
#include <string.h>
#include <stdio.h>
#include <vector>
#define MAXM 50210
#define MAXN 105
using namespace std;
typedef long long LL;
const int P=1e9+7;
const int P_=P-1;
struct Io
{
const char l='0'-1;
const char r='9'+1;
char A[MAXM*10];
char *ptop,*pend;
Io()
{
ptop=pend=A;
}
void Io_fread()
{
pend=A+fread(A,1,MAXN,stdin);
ptop=A;
}
bool read(int &a)//返回false表示什么也没读到
{
if(ptop==pend)Io_fread();
if(ptop==pend)return false;
while(*ptop==' '||*ptop=='\n'||*ptop=='\r'||*ptop=='\t')
{
ptop++;
if(ptop==pend)
{
Io_fread();
if(ptop==pend)return false;
}
}
a=0;
while(*ptop>l&&*ptop<r&&ptop<pend)
{
a=a*10+(*(ptop++)-'0');
if(ptop==pend) Io_fread();
}
return true;
}
}I;
struct node
{
int to,next;
node(int to,int next):to(to),next(next){}
node()
{
*this=node(0,0);
}
}G[MAXM];//返图。方便topsort
struct edge
{
int from,to,w,L,R,cnt;
edge(int from,int to,int w):from(from),to(to),w(w){};
edge(int to,int w,int L,int R):to(to),w(w),L(L),R(R){}
edge()
{
*this=edge(0,0,0,0);
cnt=0;
from=0;
}
}E[MAXN][20000];
vector<int>V[MAXN];
int Ginof[MAXN];
int inof[MAXN][MAXN];
int mu[MAXN]={0,-1},out[MAXN],ans[MAXN],dp[MAXN];
int F[MAXM][3],F2[MAXM][3];
int name[MAXN][MAXN];
void add(edge &e,int deep)
{
out[e.from]++;
G[deep]=node(e.from,Ginof[e.to]);
Ginof[e.to]=deep;
}
void build(int t,int deep)//将deep调边录入t集合内
{
E[t][deep].cnt++;
if(E[t][deep].cnt>1)return;
edge &e=E[t][deep];
if(!e.from)
{
e.from=F2[deep][0];
e.to=F2[deep][1];
}
int &d=inof[t][e.from];
e.L=E[t][d].L;
e.R=d;
E[t][E[t][d].L].R=deep;
E[t][d].L=deep;
}
void Remove(int t,int deep)//删除
{
E[t][deep].cnt--;
if(E[t][deep].cnt)return;
E[t][E[t][deep].L].R=E[t][deep].R;
E[t][E[t][deep].R].L=E[t][deep].L;
E[t][deep].R=E[t][deep].L=0;
}
int Q[MAXN],A[MAXN];
void topsort(int n);
int slove(int d,int n);//d倍数权重的图上计算边数;
int clat();
int main ()
{
for(int i=1;i<MAXN;i++)
{
mu[i]=-mu[i];
for(int j=i<<1;j<MAXN;j+=i)mu[j]+=mu[i];
}//计算 莫比乌斯函数。
for(int i=1;i<MAXN;i++)
for(int j=i;j<MAXN;j+=i)
V[j].push_back(i);
for(int i=1;i<101;i++)
for(int j=1;j<101;j++)
inof[i][j]=j+50002;
int n,m,x,y,T;
I.read(n);
I.read(m);
int deep=1;
for(int i=1;i<=m;i++)
{
I.read(F[i][0]);
I.read(F[i][1]);
I.read(F[i][2]);
if(name[F[i][0]][F[i][1]]==0)
{
F2[deep][0]=F[i][0];
F2[deep][1]=F[i][1];
name[F[i][0]][F[i][1]]=deep++;
}
int &d=F[i][2],&b=name[F[i][0]][F[i][1]];
for(int j=0;j<(int)V[d].size();j++)
{
int u=V[d][j];
build(u,b);
}
add(E[d][b],i);
}
topsort(n);
for(int i=1;i<101;i++)ans[i]=slove(i,n);
int ANS=clat();
printf("%d\n",ANS);
I.read(T);
while(T--)
{
I.read(x);
I.read(y);
int w=F[x][2];
F[x][2]=y;
x=name[F[x][0]][F[x][1]];
for(int i=0;i<V[w].size();i++)
{
int d=V[w][i];
Remove(d,x);
}
for(int i=0;i<V[y].size();i++)
{
int d=V[y][i];
build(d,x);
}
for(int j=1;j<V[y].size();j++)
{
int &i=V[y][j];
ANS-=mu[i]*ans[i];
if(ANS<0)ANS+=P;
if(ANS>P_)ANS-=P;
ans[i]=slove(i,n);
ANS+=mu[i]*ans[i];
if(ANS<0)ANS+=P;
if(ANS>P_)ANS-=P;
}
for(int j=1;j<V[w].size();j++)
{
int &i=V[w][j];
if(y%i)
{
ANS-=mu[i]*ans[i];
if(ANS<0)ANS+=P;
if(ANS>P_)ANS-=P;
ans[i]=slove(i,n);
ANS+=mu[i]*ans[i];
if(ANS<0)ANS+=P;
if(ANS>P_)ANS-=P;
}
}
printf("%d\n",ANS);
}
return 0;
}
void topsort(int n)
{
int l=0,r=0;
for(int i=1;i<=n;i++)
{
if(out[i])continue;
Q[r++]=i;
}
while(l<r)
{
int v=Q[l++];
A[n--]=v;
for(int i=Ginof[v];i;i=G[i].next)
{
node &e=G[i];
out[e.to]--;
if(out[e.to])continue;
Q[r++]=e.to;
}
}
}
int slove(int d,int n)
{
int tmp=0;
memset(dp,0,sizeof dp);
for(int i=n;i;i--)
{
int v=A[i];
for(int j=E[d][inof[d][v]].L;j;j=E[d][j].L)
{
edge &e=E[d][j];
dp[v]+=((LL)e.cnt*dp[e.to]+e.cnt)%P;
if(dp[v]>P_)dp[v]-=P;
}
tmp+=dp[v];
if(tmp>P_)tmp-=P;
}
return tmp;
}
int clat()
{
int tmp=0;
for(int i=1;i<101;i++)
{
tmp=(tmp+ans[i]*mu[i]);
if(tmp>P_)tmp-=P;
if(tmp<0)tmp+=P;
}
return tmp;
}