就是我的自定义函数里的dfs,怎么实现把这棵树(我转化成了有向图)填成一个小根堆的所有方案数算出来。
//并查集+树转有向图
//x连y的树的根节点之下就是find[y]->x连一条边
//先把图建对了再说
//暴搜看能出现几个小根堆,小根堆性质,每个点的权值都不小于父亲的权值
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int mod=1e9+7;
int ans,size,n,q;
int fa[100010],head[100010];
bool vis[100010];
struct node{
int nxt,to;
}edge[100010];
int idx;
void add(int u,int v)//u向v连边
{
edge[++idx].nxt=head[u];
edge[idx].to=v;
head[u]=idx;
}
int find(int x)//并查集找根
{
if(x==fa[x]) return x;
return fa[x]=find(fa[x]);
}
void get(int x)//获得这棵树的节点个数,从x(根节点)出发.
{
for(int i=head[x];i;i=edge[i].nxt)
{
int v=edge[i].to;
size++;
get(v);
}
}
void dfs(int u,int last,int cnt)//u表示当前的点,last表示它的父节点的值,cnt表示填了几个数了,选的数必须比他父节点的大,满足小根堆的性质。
{
if(cnt==size)//填满了
{
ans++;
return ;
}
for(int i=head[u];i;i=edge[i].nxt)
{
}
}
int main()
{
//freopen("heap.in","r",stdin);
//freopen("heap.out","w",stdout);
cin>>n>>q;
for(int i=0;i<=n-1;i++)//初始化并查集,编号是0到n-1
{
fa[i]=i;
}
for(int i=1;i<=q;i++)
{
int op,x,y;
scanf("%d",&op);
if(op==1)//把真正的x的根接在y的根下面。
{
scanf("%d%d",&x,&y);
x=(x+ans)%n;//真正的x
y=(y+ans)%n;//真正的y
y=find(y);//y所在树的根
x=find(x);//x所在树的根
add(y,x);//树上连边
fa[x]=y;
size=1;
get(y);
//cout<<y<<" "<<size<<endl;
}
else if(op==2)//op==2的时候记录ans,下一次op==1的时候要用
{
scanf("%d",&x);
x=(x+ans)%n;//真正的x
x=find(x);//x所在树的根
size=1;//自己这个点也算
ans=0;//每次ans要重置
get(x);//找出x所在树的节点数;
vis[0]=1;
dfs(x,0,1);//从根开始填数,根节点必须填0。
printf("%d\n",ans);
}
}
return 0;
}