傳送門
題解:
樹的部分直接點分治+NTT合併算出所有距離有多少點對即可。
有環的話,再上一個分治即可。
代碼:
#include<bits/stdc++.h>
#define ll long long
#define re register
#define cs const
namespace IO{
inline char gc(){
static cs int Rlen=1<<22|1;static char buf[Rlen],*p1,*p2;
return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,Rlen,stdin),p1==p2)?EOF:*p1++;
}template<typename T>T get_integer(){
char c;bool f=false;while(!isdigit(c=gc()))f=c=='-';T x=c^48;
while(isdigit(c=gc()))x=((x+(x<<2))<<1)+(c^48);return f?-x:x;
}inline int gi(){return get_integer<int>();}
}using namespace IO;
using std::cerr;
using std::cout;
cs int mod=998244353;
inline int add(int a,int b){return a+b>=mod?a+b-mod:a+b;}
inline int dec(int a,int b){return a-b<0?a-b+mod:a-b;}
inline int mul(int a,int b){ll r=(ll)a*b;return r>=mod?r%mod:r;}
inline void Inc(int &a,int b){a+=b-mod;a+=a>>31&mod;}
inline void Dec(int &a,int b){a-=b;a+=a>>31&mod;}
inline void Mul(int &a,int b){a=mul(a,b);}
inline int po(int a,int b){int r=1;for(;b;b>>=1,Mul(a,a))if(b&1)Mul(r,a);return r;}
inline void ex_gcd(int a,int b,int &x,int &y){
if(!b){x=1,y=0;return;}ex_gcd(b,a%b,y,x);y-=a/b*x;
}inline int Inv(int a){static int x,y;ex_gcd(mod,a,y,x);return x+(x>>31&mod);}
cs int bit=19,SIZE=1<<bit|7;
int r[SIZE],*w[bit+1],Log[SIZE];
void init_omega(){
for(int re i=1;i<=bit;++i)
w[i]=new int[1<<(i-1)];
int wn=po(3,(mod-1)>>bit);w[bit][0]=1;
for(int re i=1;i<(1<<(bit-1));++i)
w[bit][i]=mul(w[bit][i-1],wn);
for(int re i=bit-1;i;--i)
for(int re j=0;j<(1<<(i-1));++j)
w[i][j]=w[i+1][j<<1];
for(int re i=2;i<SIZE;++i)
Log[i]=Log[i-1]+((1<<Log[i-1])<i);
}
int len,inv_len;
void init_len(int deg){
int l=1;while(l<deg)l<<=1;
len=l,inv_len=Inv(l);
for(int re i=1;i<l;++i)
r[i]=r[i>>1]>>1|((i&1)?l>>1:0);
}void DFT(int *A){
for(int re i=1;i<len;++i)
if(i<r[i])std::swap(A[i],A[r[i]]);
for(int re i=1,d=1;i<len;i<<=1,++d)
for(int re j=0;j<len;j+=i<<1)
if(i<8){
for(int re k=0;k<i;++k){
int &t1=A[j+k],&t2=A[i+j+k];
int t=mul(t2,w[d][k]);
t2=dec(t1,t),Inc(t1,t);
}
}else {
#define work(p) \
{ \
int &t1=A[j+k+p],&t2=A[i+j+k+p]; \
int t=mul(t2,w[d][k+p]); \
t2=dec(t1,t),Inc(t1,t); \
}
for(int re k=0;k<i;k+=8){
work(0);work(1);work(2);work(3);
work(4);work(5);work(6);work(7);
}
}
}void IDFT(int *A){
DFT(A);std::reverse(A+1,A+len);
for(int re i=0;i<len;++i)Mul(A[i],inv_len);
}
typedef std::vector<int> Poly;
inline void DFT(Poly &A){DFT(&A[0]);}
inline void IDFT(Poly &A){IDFT(&A[0]);}
Poly sqr(Poly a){
if(!a.size())return a;int deg=a.size()*2-1;
init_len(deg);a.resize(len);DFT(a);
for(int re i=0;i<len;++i)Mul(a[i],a[i]);IDFT(a);
return Poly(a.begin(),a.begin()+deg);
}
cs int N=1e5+7;
int n,k,ans[N];
std::vector<int> G[N];
int fa[N],d[N],nd[N],nct;
bool find_loop(int u,int p){
d[u]=d[p]+1;fa[u]=p;
for(int re v:G[u])
if(v!=p){
if(!d[v]){
if(find_loop(v,u))
return true;
}else if(d[v]<=d[u]){
int nw=u;nct=0;
while(nw!=fa[v]){
nd[++nct]=nw;nw=fa[nw];
}return true;
}
}return false;
}
Poly p[N];
int Mx,Gr,total;
bool ban[N];
int sz[N],ct[N],mxd;
void get_dis(int u,int p,int d,Poly &f){
sz[u]=1;for(int re v:G[u])if(v!=p&&!ban[v])
get_dis(v,u,d+1,f),sz[u]+=sz[v];
while(f.size()<d+1u)f.push_back(0);++f[d];
}
void get_G(int u,int p){
int mx=total-sz[u];
for(int re v:G[u])if(v!=p&&!ban[v])
get_G(v,u),mx=std::max(mx,sz[v]);
if(mx<Mx)Mx=mx,Gr=u;
}
void solve_G(int u){
ban[u]=true;Poly f;
for(int re v:G[u])if(!ban[v]){
Poly g;get_dis(v,u,0,g);
if(f.size()<g.size())
f.resize(g.size());
for(size_t re i=0;i<g.size();++i)
Inc(f[i],g[i]);
g=sqr(g);
for(size_t re i=0;i<g.size();++i)
Dec(ans[i+2],g[i]);
Mx=total=sz[v],Gr=-1;
get_G(v,u);solve_G(Gr);
}for(size_t re i=0;i<f.size();++i)
Inc(ans[i+1],mul(f[i],2));
f=sqr(f);
for(size_t re i=0;i<f.size();++i)
Inc(ans[i+2],f[i]);
}
int A[SIZE],ta,B[SIZE],tb;
void add_ans(int l1,int r1,int l2,int r2,int gap){
ta=tb=0;
for(int re i=l1;i<=r1;++i){
for(size_t re j=0;j<p[i].size();++j)
Inc(A[j+r1-i],p[i][j]);
ta=std::max<int>(ta,p[i].size()+r1-i);
}for(int re i=l2;i<=r2;++i){
for(size_t re j=0;j<p[i].size();++j)
Inc(B[j-l2+i],p[i][j]);
tb=std::max<int>(tb,p[i].size()-l2+i);
}init_len(ta+tb-1);DFT(A),DFT(B);
for(int re i=0;i<len;++i)
Mul(A[i],B[i]);IDFT(A);
for(int re i=0;i<ta+tb-1;++i)
Inc(ans[i+gap],A[i]);
memset(A,0,sizeof(int)*len);
memset(B,0,sizeof(int)*len);
}
int find_mid(int l,int r){
int m=std::lower_bound(sz+l,sz+r+1,(sz[l]+sz[r])>>1)-sz;
if(m==r)--m;return m;
}
void solve_inside(int l,int r){
if(l==r)return;
int m=find_mid(l,r);
add_ans(l,m,m+1,r,1);
solve_inside(l,m);
solve_inside(m+1,r);
}
void solve_loop(int l1,int r1,int l2,int r2,int gap){
if(l1==r1)return add_ans(l1,r1,l2,r2,gap);
int m1=find_mid(l1,r1),m2=l2+m1-l1;
add_ans(m1+1,r1,l2,m2,gap);
solve_loop(l1,m1,l2,m2,gap+r1-m1);
solve_loop(m1+1,r1,m2+1,r2,gap+m1-l1+1);
}
void Main(){
init_omega();
n=gi(),k=gi()%(mod-1);bool fl=false;
for(int re i=1;i<=n;++i){
int u=gi(),v=gi();
if(u!=v){
G[u].push_back(v);
G[v].push_back(u);
}else fl=true;
}if(!fl)find_loop(1,0);else nd[++nct]=1;
for(int re i=1;i<=nct;++i)
ban[nd[i]]=true;
for(int re i=1;i<=nct;++i){
ban[nd[i]]=false;
get_dis(nd[i],0,0,p[i]);
Mx=total=sz[nd[i]],Gr=-1;
get_G(nd[i],0);solve_G(Gr);
}for(int re i=1;i<=n;++i)
Mul(ans[i],(mod+1)/2);
if(nct>1){
int hl=nct/2;
sz[0]=0;for(int re i=1;i<=hl;++i)
sz[i]=sz[i-1]+p[i].size();
solve_inside(1,hl);
sz[hl]=0;for(int re i=hl+1;i<=nct;++i)
sz[i]=sz[i-1]+p[i].size();
solve_inside(hl+1,nct);
sz[0]=0;for(int re i=1;i<=hl;++i)
sz[i]=sz[i-1]+p[i].size()+p[hl+i].size();
solve_loop(1,hl,hl+1,hl+hl,1);
sz[hl+1]=0;for(int re i=hl+2;i<=nct;++i)
sz[i]=sz[i-1]+p[i].size()+p[i-hl-1].size();
solve_loop(hl+2,nct,1,nct-hl-1,1);
}int res=0;
for(int re i=1;i<=n;++i)
Inc(res,mul(po(i,k),ans[i]));
cout<<mul(res,Inv(n*(n-1ll)/2%mod));
}
inline void file(){
#ifdef zxyoi
freopen("dis.in","r",stdin);
#endif
}signed main(){file();Main();return 0;}