qoj4885 Triangular Cactus Paths

题意

给出一个环长度最多为 \(3\) 的简单仙人掌图,\(q\) 个询问,每次询问给出 \(s,f,k\),求 \(s\) 到 \(f\) 长度恰好为 \(k\) 的简单路径数量。

思路

仙人掌图显然圆方树,但是因为环长度最多为 \(3\),所以 tarjan 都省了。

询问首先求出 \(s\) 到 \(f\) 的最长路径长度(就是圆方树上的路径长度)\(d\) 和经过的环的数量(即方点数量)\(c\)。

从环上的一个点到另一个点,可以走 \(1\) 步,也可以走 \(2\) 步。

因此为了使得路径长度为 \(k\),我们需要在 \(d-k\) 个环上走一步,其他环上走两步。

显然不同的方案数为 \(\binom{c}{d-k}\),注意判无解。

代码

#include <bits/stdc++.h>
using namespace std;
#define ll long long
ll fpow(ll x,ll y,ll p){
	ll res=1,t=x;
	while(y){
		if(y&1) res=(res*t)%p;
		t=(t*t)%p,y>>=1;
	}
	return res;
}
const ll md=998244353;
ll fp[200005],inv[200005];
ll C(int x,int y){
	return fp[x]*inv[y]%md*inv[x-y]%md;
}
int n,m,tot,dep[400005],cnt[400005],f[400005][25],q;
vector<int> t[400005],t2[400005];
map<pair<int,int>,bool> ct;
bool vis[400005];
void dfs(int x,int fa){
	vis[x]=true;
	for(int v:t2[x]){
		if(v!=fa){
			if(vis[v]){
				if(ct[{x,v}]) continue;
				ct[{x,v}]=ct[{v,x}]=ct[{x,fa}]=ct[{fa,x}]=ct[{v,fa}]=ct[{fa,v}]=true;
				tot++;
				t[x].push_back(tot);
				t[tot].push_back(x);
				t[fa].push_back(tot);
				t[tot].push_back(fa);
				t[v].push_back(tot);
				t[tot].push_back(v);
			}
			else
				dfs(v,x);
		}
	}
}
void dfs2(int x,int fa){
	dep[x]=dep[fa]+1;
	cnt[x]=cnt[fa]+(x>n);
	f[x][0]=fa;
	for(int i=1;i<=20;i++)
		f[x][i]=f[f[x][i-1]][i-1];
	for(int v:t[x])
		if(v!=fa) dfs2(v,x);
}
int lca(int x,int y){
	if(dep[x]<dep[y]) swap(x,y);
	for(int i=20;i>=0;i--)
		if(dep[f[x][i]]>=dep[y]) x=f[x][i];
	if(x==y) return x;
	for(int i=20;i>=0;i--)
		if(f[x][i]!=f[y][i]) x=f[x][i],y=f[y][i];
	return f[x][0];
}
signed main() {
	ios::sync_with_stdio(false);
	cin.tie(nullptr),cout.tie(nullptr);
	cin>>n>>m;
	fp[0]=inv[0]=1;
	for(int i=1;i<=200000;i++)
		fp[i]=fp[i-1]*i%md,inv[i]=fpow(fp[i],md-2,md);
	tot=n;
	for(int x,y,i=1;i<=m;i++){
		cin>>x>>y;
		t2[x].push_back(y);
		t2[y].push_back(x);
	}
	dfs(1,0);
	for(int i=1;i<=n;i++)
		for(int v:t2[i])
			if(!ct[{i,v}])
				t[i].push_back(v);
	dfs2(1,0);
	cin>>q;
	while(q--){
		int x,y,k,l,d,c;
		cin>>x>>y>>k;
		l=lca(x,y);
		d=dep[x]+dep[y]-2*dep[l];
		c=cnt[x]+cnt[y]-2*cnt[l]+(l>n);
		if(d-k<0||d-k>c) cout<<0<<endl;
		else cout<<C(c,d-k)<<endl;
	}
	return 0;
}
posted @ 2025-09-02 20:06  WuMin4  阅读(46)  评论(0)    收藏  举报