Description
Input
Output
Sample Input
1 2
2 3
3 4
2 5
3 5
2 5
1 4
Sample Output
樣例解釋
可以選擇的路徑對有(1,2),(1,3),(2,3),只有路徑1完全覆蓋路徑2。
附:這道題真的是精神污染
機房的人RE和MLE記錄:
我們可以通過兩種方式計算答案:1.算出每條路徑覆蓋幾條路徑
2.計算每條路徑被幾條路徑覆蓋
那麼這道題是從第一個角度考慮,對於一條路徑(u,v)任意選取一個端點,假設把u作爲端點,把v塞入u的動態數組中,然後對整顆樹進行dfs,求出歐拉序,再對整棵樹進行第二遍dfs,把動態數組中對應的節點在L處加1,R處減1,那麼在統計答案的時候對選定端點的限制體現在主席樹選用的根爲root[u],root[v],root[lca(u,v)],root[f[lca(u,v)][0]],限制了選定端點,然後進行區間查詢,查詢[L[lca],L[u]]和[L[lca],L[v]],因爲L[lca]被算了兩遍,所以要再次減去L[lca]的貢獻,而且不能算上自己在L[u]或L[v]的貢獻,然後Ans需要減1,然後就得到答案了。炸int注意。。。
code:
#include <stdio.h>
#include <cstring>
#include <vector>
const int MAXN = 100005;
typedef long long ll;
int first[MAXN],e=1,deep[MAXN],f[MAXN][20],size,cnt,root[MAXN],L[MAXN],R[MAXN],n,m;
std :: vector<int>G[MAXN];
template<typename _t>
inline _t read(){
_t x=0,f=1;
char ch=getchar();
for(;ch>'9'||ch<'0';ch=getchar())if(ch=='-')f=-f;
for(;ch>='0'&&ch<='9';ch=getchar())x=x*10+(ch^48);
return x*f;
}
ll gcd(ll x,ll y){return y==0?x:gcd(y,x%y);}
struct node{
int l,r,sum;
}tree[MAXN*39];
void insert(int &o,int old,int l,int r,int pos,int val){
o=++cnt;
tree[o]=tree[old];
tree[o].sum+=val;
if(l==r)return;
int m=l+r>>1;
if(pos<=m)insert(tree[o].l,tree[old].l,l,m,pos,val);
else insert(tree[o].r,tree[old].r,m+1,r,pos,val);
}
#define l(x) tree[x].l
#define r(x) tree[x].r
#define s(x) tree[x].sum
inline ll Query(int t1,int t2,int t3,int t4,int x,int y,int l,int r){
if(x<=l&&r<=y)return s(t1)+s(t2)-s(t3)-s(t4);
ll Ans = 0;int m=l+r>>1;
if(x<=m)Ans+=Query(l(t1),l(t2),l(t3),l(t4),x,y,l,m);
if(m<y)Ans+=Query(r(t1),r(t2),r(t3),r(t4),x,y,m+1,r);
return Ans;
}
struct edge{
int v,next;
}a[MAXN<<1];
struct Query{
int x,y;
}q[MAXN];
inline void push(int u,int v){
a[e].v=v;a[e].next=first[u];
first[u]=e++;
}
void dfs(int u,int fa){
L[u]=++size;
f[u][0]=fa;deep[u]=deep[fa]+1;
for(int i=1;i<=17;i++)
f[u][i]=f[f[u][i-1]][i-1];
for(int i=first[u];i;i=a[i].next)
if(a[i].v!=fa)dfs(a[i].v,u);
R[u]=++size;
return;
}
void __dfs(int u){
root[u]=root[f[u][0]];
for(int i=0;i<G[u].size();i++)
insert(root[u],root[u],1,size,L[G[u][i]],1),
insert(root[u],root[u],1,size,R[G[u][i]],-1);
for(int i=first[u];i;i=a[i].next)
if(a[i].v!=f[u][0])
__dfs(a[i].v);
}
inline int lca(int u,int v){
if(deep[u]<deep[v]){u^=v;v^=u;u^=v;}
int t=deep[u]-deep[v];
for(int i=0;i<=17;i++)
if(t&(1<<i))
u=f[u][i];
if(u==v)return u;
for(int i=17;i>=0;i--)
if(f[u][i]!=f[v][i])
u=f[u][i],v=f[v][i];
return f[u][0];
}
int main(){
n=read<int>();m=read<int>();
for(int i=1;i<n;i++){
int u=read<int>(),v=read<int>();
push(u,v);push(v,u);
}
dfs(1,0);
for(int i=1;i<=m;i++)q[i].x=read<int>(),q[i].y=read<int>(),G[q[i].x].push_back(q[i].y);
__dfs(1);
ll Ans = 0;
for(int i=1;i<=m;i++){
int Lca=lca(q[i].x,q[i].y);
int t1=root[q[i].x],t2=root[q[i].y],t3=root[Lca],t4=root[f[Lca][0]];
Ans+=Query(t1,t2,t3,t4,L[Lca],L[q[i].x],1,size);
Ans+=Query(t1,t2,t3,t4,L[Lca],L[q[i].y],1,size);
Ans-=Query(t1,t2,t3,t4,L[Lca],L[Lca],1,size);
Ans--;
}
if(Ans==0){
printf("0/1\n");
return 0;
}
ll tmp = gcd(Ans,(ll)m*(m-1)/2);
printf("%lld/%lld\n",Ans/tmp,(ll)m*(m-1)/2/tmp);
}