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  阅读(22)  评论(0)    收藏  举报