有一个显而易见的道理,一条边,比如说连接到
的一条边,从
出发,如果走偶数次,还是会回到
,所以对于每次询问,对于不在最简路径上的边,如果要求至少偶数次,那就走偶数次;奇数次的话,就++。对于最短路径上的,要走奇数次,不然就又回去了。直接查询肯定不好,所以先预处理出整个树的偶数次之和,设为
,再减去最简路径的偶数次
,加上最简路径的奇数次
,处理
和
用lca。
代码如下
#include<bits/stdc++.h> #define ll long long #define mod 1000000007 using namespace std; const int maxn=100005; int head[maxn],tot,f[maxn][25],dep[maxn]; ll odd[maxn],eve[maxn],n,m; struct Edge{ int v,w,nxt,t; }e[maxn<<1]; void add(int u,int v,int w,int t) { e[++tot].v=v; e[tot].w=w; e[tot].t=t; e[tot].nxt=head[u]; head[u]=tot; } void dfs(int u,int fa) { dep[u]=dep[fa]+1; f[u][0]=fa; for(int i=1;(1<<i)<=dep[u];i++) f[u][i]=f[f[u][i-1]][i-1]; for(int i=head[u];i;i=e[i].nxt) { int v=e[i].v; if(v==fa) continue; int w=e[i].w; int t=e[i].t; if(t%2) { odd[v]=(odd[u]+1LL*t*1LL*w%mod)%mod; eve[v]=(eve[u]+1LL*(t+1)*1LL*w%mod)%mod; } else { odd[v]=(odd[u]+1LL*(t+1)*1LL*w%mod)%mod; eve[v]=(eve[u]+1LL*t*1LL*w%mod)%mod; } dfs(v,u); } } int lca(int x,int y) { if(dep[x]>dep[y]) swap(x,y); for(int i=20;i>=0;i--) { if(dep[y]-(1<<i)>=dep[x]) y=f[y][i]; } if(x==y) return x; for(int i=20;i>=0;i--) { if(f[x][i]==f[y][i]) continue; x=f[x][i]; y=f[y][i]; } return f[x][0]; } int main() { scanf("%d",&n); ll res=0; for(int i=1;i<=n-1;i++) { int x,y,z,t; scanf("%d%d%d%d",&x,&y,&z,&t); add(x,y,z,t); add(y,x,z,t); if(t%2) t++; res+=1LL*z*t; res%=mod; } dfs(1,0); scanf("%d",&m); for(int i=1;i<=m;i++) { int x,y; scanf("%d%d",&x,&y); int l=lca(x,y); ll a1=((odd[x]-odd[l]+mod)%mod+(odd[y]-odd[l]+mod)%mod)%mod; ll a2=((eve[x]-eve[l]+mod)%mod+(eve[y]-eve[l]+mod)%mod)%mod; printf("%lld\n",(res-a2+a1+mod)%mod); } return 0; }