G. Rikka with Intersections of Paths
time limit per test
6.0 s
memory limit per test
1024 MB
input
standard input
output
standard output
Rikka has a tree TT with nn vertices numbered from 11 to nn.
Meanwhile, Rikka has marked mm simple paths in TT, the ii-th of which is between the vertices xixi and yiyi, where some of them could be the same path.
Now, Rikka wants to know in how many different strategies she can select kk paths from the marked paths such that those selected paths share at least one common vertex.
Input
The input contains several test cases, and the first line contains a single integer TT (1≤T≤2001≤T≤200), the number of test cases.
For each test case, the first line contains three integers nn (1≤n≤3×1051≤n≤3×105), the size of the tree TT, mm (2≤m≤3×1052≤m≤3×105), the number of marked paths, and kk (2≤k≤m2≤k≤m).
The following (n−1)(n−1) lines describe the tree TT. Each of them contains two integers uu and vv (1≤u,v≤n1≤u,v≤n, u≠vu≠v), representing an edge between the vertices uu and vv.
The following mm lines describe all marked simple paths in the tree. The ii-th of them contains two integers xixi and yiyi (1≤xi,yi≤n1≤xi,yi≤n).
The input guarantees that the sum of nn and the sum of mm in all test cases are at most 2×1062×106 respectively.
Output
For each test case, output a single line with a single integer, the number of different strategies meeting the requirement modulo (109+7)(109+7).
Example
input
Copy
1 3 6 2 1 2 1 3 1 1 2 2 3 3 1 2 1 3 2 3
output
Copy
10
题意:给出一个n个的无向图,n-1条边。并给出m条被标记的边,问有多少种方案选k条被标记的路径使得它们至少有一个公共的顶点。
学过树上差分的话应该可以从题目的要求看出端倪这题用树上差分,至于为何是这样的组合数计算方式,to be hones,我也还没懂。
#include <bits/stdc++.h>
using namespace std;
const int N=300000+200;
typedef long long ll;
int n,m,ans;
#define mod 1000000007
ll fac[N]={1,1},inv[N]={1,1},f[N]={1,1};
struct LCA
{
int head[N<<1],Next[N<<1],edge[N<<1],ver[N<<1],tot=0;
int deep[N],fa[N][22],lg[N],date[N],date1[N];
inline void init()
{
memset(head,0,sizeof(head));
memset(deep,0,sizeof(deep));
memset(fa,0,sizeof fa);
memset(lg,0,sizeof lg);
memset(date1,0,sizeof date1);
memset(date,0,sizeof date);
tot=0;
}
inline void add_edge(int a,int b,int c)
{
edge[++tot]=b;
ver[tot]=a;
Next[tot]=head[a];
head[a]=tot;
}
inline void dfs(int x,int y)
{
deep[x]=deep[y]+1;
fa[x][0]=y;
for(int i=1; (1<<i)<=deep[x]; i++)
fa[x][i]=fa[fa[x][i-1]][i-1];
for(int i=head[x]; i; i=Next[i])
if (edge[i]!=y)
dfs(edge[i],x);
return ;
}
inline int Lca(int x,int y)
{
if (deep[x]<deep[y])
swap(x,y);
while(deep[x]>deep[y])
x=fa[x][lg[deep[x]-deep[y]]-1];
if(x==y)
return x;
for(int i=lg[deep[x]]; i>=0; i--)
if (fa[x][i]!=fa[y][i])
{
x=fa[x][i];
y=fa[y][i];
}
return fa[x][0];
}
inline void query(int x,int f)
{
for(int i=head[x]; i; i=Next[i])
{
int j=edge[i];
if (j!=f)
{
query(j,x);
date[x]+=date[j];
date1[x]+=date1[j];
}
}
}
inline void update(int x,int y)
{
int z=Lca(x,y);
date[x]++;
date[y]++;
date[z]-=2;
date1[x]++;
date1[y]++;
date1[z]--;
date1[fa[z][0]]--;
}
inline ll C(int a,int b)
{
if (a<b) return 0;
return fac[a]*inv[b]%mod*inv[a-b]%mod;
}
inline ll getans(int k)
{
ll ans=0;
for(int i=1;i<=n;i++)
{
ans=(ans+C(date1[i],k)%mod)%mod;
}
for(int i=2;i<=n;i++)
{
ans=(ans-C(date[i],k)%mod+mod)%mod;
}
return (ans%mod);
}
} g1;
void init()
{
for(int i=2;i<300010;i++)
{
fac[i]=fac[i-1]*i%mod;
f[i]=(mod-mod/i)*f[mod%i]%mod;
inv[i]=inv[i-1]*f[i]%mod;
}
}
int main()
{
init();
int T;
scanf("%d",&T);
while(T--)
{
int k;
scanf("%d%d%d",&n,&m,&k);
g1.init();
for(int i=1; i<n; i++)
{
int a,b;
scanf("%d%d",&a,&b);
g1.add_edge(a,b,0);
g1.add_edge(b,a,0);
}
for(int i=1; i<=n; i++)
g1.lg[i]=g1.lg[i-1]+(1<<g1.lg[i-1]==i);
g1.dfs(1,0);
for(int i=1; i<=m; i++)
{
int a,b;
scanf("%d%d",&a,&b);
g1.update(a,b);
}
g1.query(1,0);
printf("%lld\n",g1.getans(k));
}
return 0;
}