[51nod1610]路径计数
路径上所有边权的最大公约数定义为一条路径的值。
给定一个有向无环图。
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行,修改前和每次修改操作后输出答案。
朴素的想法...一开始先求出f[i][j]表示在DAG上从i点开始的路径的值为j的方案数,然后每次修改边权的时候,只要求g[i][j]表示从i点开始,经过修改的那条边的路径的值为j的方案数,然后更新f[i][j]就好了(修改就是一次删除一次添加)。
为了跑得快一点...可以先求出拓扑序、预处理出每个点可以到达哪些点、修改的时候先计算一下有哪些路径值可能被影响...以避免不必要的计算和更新T_T
复杂度O(100*n*m+T*因子个数*m)大概4亿左右...最后900+ms险过..
正解是容斥、floyd....其实复杂度和正解也差不多?(常数感人
值为1的路径数量= sum{ 值为x的倍数的路径数量∗u[x] } ,1<=x<=100, u[x] 为莫比乌斯函数。
值为x的倍数的路径数量可以把所有边权为x的倍数的边取出来计算路径条数。
dp[x][i][j]表示只考虑所有边权为x的倍数的边时,点i到点j的路径数量。初始化的时候,枚举x,然后跑一次floyd即可。
那么删除一条边权为k的倍数的、从x到y的边,可以用如下代码完成:1 for(i=1;i<=n;++i) 2 { 3 for(j=1;j<=n;j++) 4 { 5 dp[k][i]][j]-=dp[k][i][x]*dp[k][y][j]; 6 } 7 }添加一条边类似,如此便可以做到修改边权的操作。
时间复杂度 O(100∗n^3+T∗因子个数∗n^2) 。
1 #include<cstdio> 2 #include<iostream> 3 #include<cstring> 4 #include<algorithm> 5 #include<queue> 6 #include<cmath> 7 #include<bitset> 8 #define ll long long 9 #define ui unsigned int 10 #define ull unsigned long long 11 #define d double 12 const int maxn=105,mxm=50023,modd=1000000007; 13 struct zs1{int too,pre,dis;}e[mxm];int tot,last[maxn],x[mxm],y[mxm],val[mxm]; 14 struct zs{int zt,id;}a[maxn];int cnt; 15 int p[maxn],np,mn[maxn],bel[maxn],zt[maxn]; 16 int dl[maxn],pos[maxn],deg[maxn],too[66][maxn]; 17 int f[maxn][66],g[maxn][9]; 18 int i,j,k,n,m; 19 char s[maxn]; 20 21 int ra;char rx; 22 inline int read(){ 23 rx=getchar(),ra=0; 24 while(rx<'0'||rx>'9')rx=getchar(); 25 while(rx>='0'&&rx<='9')ra*=10,ra+=rx-48,rx=getchar();return ra; 26 } 27 28 29 inline void MOD(int &x){if(x>=modd)x-=modd;} 30 inline void UPD(int &x){if(x<0)x+=modd;if(x>=modd)x-=modd;} 31 32 bool cmpa(zs a,zs b){return a.zt<b.zt;} 33 inline void prerun(){ 34 a[1]=(zs){0,1}; 35 for(i=2;i<=100;i++){ 36 for(j=1;j<=np;j++)if(!(i%p[j]))break; 37 if(j>np)p[++np]=i,mn[i]=np;else mn[i]=j; 38 int tmp=i; 39 while(tmp>1)a[i].zt|=1<<(mn[tmp]-1),tmp/=p[mn[tmp]]; 40 a[i].id=i; 41 } 42 cnt=0,a[0].zt=-233, 43 std::sort(a+1,a+1+100,cmpa); 44 for(i=1;i<=100;bel[a[i].id]=cnt,i++) 45 if(a[i].zt!=a[i-1].zt)zt[++cnt]=a[i].zt; 46 47 for(i=0;i<=cnt;i++)for(j=1;j<=100;j++){ 48 int now=zt[bel[j]],k; 49 if(i)now&=zt[i]; 50 for(k=1;zt[k]!=now;k++); 51 too[i][j]=k; 52 } 53 } 54 55 inline void insert(int a,int b,int c){e[++tot].too=b,e[tot].dis=c,e[tot].pre=last[a],last[a]=tot;} 56 57 std::bitset<105> con[105]; 58 inline void topo(){ 59 int l=0,r=0,i,j,now,to; 60 for(i=1;i<=n;i++){ 61 con[i][i]=1; 62 if(!deg[i])dl[++r]=i; 63 } 64 for(i=1;i<=n;i++)f[i][0]=1; 65 while(l<r)for(i=last[now=dl[++l]];i;i=e[i].pre){ 66 to=e[i].too, 67 con[to]|=con[now]; 68 if(!--deg[to])dl[++r]=to; 69 for(j=0;j<=cnt;j++)MOD(f[to][too[j][e[i].dis]]+=f[now][j]); 70 } 71 for(i=1;i<=n;i++)pos[dl[i]]=i; 72 } 73 74 int mp[23],id[maxn]; 75 inline void getg(int edge,int fh){ 76 register int i,j,k; 77 int e_id=bel[val[edge]],e_x=x[edge],e_y=y[edge],e_dis=val[edge]; 78 int num=0,now,to; 79 for(i=1;i<=cnt;i++)if((zt[i]&zt[e_id])==zt[i])mp[++num]=i,id[i]=num; 80 81 memset(g[e_x]+1,0,num<<2); 82 for(i=0;i<=cnt;i++)if(f[e_y][i])MOD(g[e_x][id[too[i][e_dis]]]+=f[e_y][i]); 83 for(i=pos[e_x]+1;i<=n;i++){ 84 if(!con[now=dl[i]][e_y])continue; 85 for(j=1;j<=num;j++)g[now][j]=0; 86 for(j=last[now];j;j=e[j].pre)if(con[(to=e[j].too)][e_x]) 87 for(k=num;k;k--) 88 MOD(g[now][id[too[mp[k]][e[j].dis]]]+=g[to][k]); 89 } 90 for(i=pos[e_x];i<=n;i++)if(con[now=dl[i]][e_x]) 91 for(j=num;j;j--)if(g[now][j])UPD(f[now][mp[j]]+=fh*g[now][j]); 92 } 93 94 95 inline int getans(){ 96 int ans=0;for(int i=1;i<=n;i++)MOD(ans+=f[i][1]); 97 return ans; 98 } 99 int main(){ 100 prerun(); 101 n=read(),m=read(); 102 for(i=1;i<=m;i++) 103 x[i]=read(),y[i]=read(),val[i]=read(), 104 deg[x[i]]++,insert(y[i],x[i],val[i]); 105 topo(),printf("%d\n",getans()); 106 107 int tmp=tot;tot=0,memset(last+1,0,n<<2); 108 for(i=1;i<=tmp;i++)insert(x[i],y[i],val[i]); 109 110 for(int q=read();q;q--){ 111 int edge=read(),v=read(); 112 getg(edge,-1),val[edge]=e[edge].dis=v,getg(edge,1),printf("%d\n",getans()); 113 } 114 }