【2019集訓隊互測】最短路徑(點分治)(NTT)(分治)

傳送門


題解:

樹的部分直接點分治+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;}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章