其实就是BZOJ3899的加强版
当时写的东西真是不敢恭维
还是看Po姐的题解吧
我们把仙人掌拆成圆方树 就可以直接用树hash来做
先找重心 因为我写的时候把两个点也当做点双 那么所有边都是圆方相接如果重心有两个 去代表环的方点就好了
接下来是hash 圆点没问题 子树排完序hash 顺带记一下如果有相同 答案乘上出现次数的阶乘
不是根的方点 也就是一个环 是有顺序的 不能排序 然后看一下翻转是不是一样 乘个2
最后如果根是一个方点 那么我们要考虑环的同构 环翻转前后跑一通KMP就知道有几种情况是循环同构的 乘上答案
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<stack>
#include<set>
using namespace std;
typedef unsigned long long ull;
typedef long long ll;
typedef pair<int,int> abcd;
inline char nc(){
static char buf[100000],*p1=buf,*p2=buf;
return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
inline void read(int &x){
char c=nc(),b=1;
for (;!(c>='0' && c<='9');c=nc()) if (c=='-') b=-1;
for (x=0;c>='0' && c<='9';x=x*10+c-'0',c=nc()); x*=b;
}
const int N=100005,P=1e9+3;
int prime[N],num;
int q[N];
int vst[N],d[N];
inline void Pre(int n){
for (int i=2;i<=n;i++){
if (!vst[i]) prime[++num]=i,d[i]=i;
for (int j=1;j<=num && (ll)i*prime[j]<=n;j++){
vst[i*prime[j]]=1; d[i*prime[j]]=prime[j];
if (i%prime[j]==0) break;
}
}
}
int _q[N];
inline void Print(int n){
for (int i=n;i;i--){
_q[i]+=_q[i+1];
if (_q[i]){
int t=i;
while (t>1)
q[d[t]]+=_q[i],t/=d[t];
}
}
int tot=0;
for (int i=1;i<=n;i++) tot+=q[i]!=0;
printf("%d\n",tot);
for (int i=1;i<=n;i++)
if (q[i])
printf("%d %d\n",i,q[i]);
}
const ull ORI1=2333,ORI2=23333;
const ull BASE1=999911657,BASE2=999911659;
const ull END1=18357,END2=81643;
struct edge{
int u,v,next;
}G[N<<1];
int head[N],inum=1;
#define V G[p].v
inline void add(int u,int v){
int p=++inum; G[p].u=u; G[p].v=v; G[p].next=head[u]; head[u]=p;
}
int n,m,bcc;
int size[N],minv=1<<30,rt;
inline void Root(int u,int fa){
size[u]=1; int maxv=0;
for (int p=head[u];p;p=G[p].next)
if (V!=fa)
Root(V,u),size[u]+=size[V],maxv=max(maxv,size[V]);
maxv=max(maxv,n+bcc-size[u]);
if (maxv<minv || (maxv==minv && u>rt)) rt=u,minv=maxv;
}
ull lst[N]; int pnt;
ull H[N];
int nxt[N];
ull b[N];
inline int KMP(ull *a,int n){
int k=0; nxt[1]=0;
for (int i=2;i<=n;i++){
while (k && a[k+1]!=a[i]) k=nxt[k];
if (a[k+1]==a[i]) k++;
nxt[i]=k;
}
for (int i=1;i<=n;i++) b[i]=b[n+i]=a[i];
k=0; int ret=0;
for (int i=1;i<n+n;i++){
while (k && a[k+1]!=b[i]) k=nxt[k];
if (a[k+1]==b[i]) k++;
if (k==n) k=nxt[k],ret++;
}
if (n>2){
reverse(b+1,b+n+n+1); k=0;
for (int i=1;i<n+n;i++){
while (k && a[k+1]!=b[i]) k=nxt[k];
if (a[k+1]==b[i]) k++;
if (k==n) k=nxt[k],ret++;
}
}
return ret;
}
inline void dfs(int u,int fa){
for (int p=head[u];p;p=G[p].next)
if (V!=fa)
dfs(V,u);
pnt=0;
if (u<=n){
for (int p=head[u];p;p=G[p].next)
if (V!=fa)
lst[++pnt]=H[V];
sort(lst+1,lst+pnt+1);
int tmp=0;
for (int i=1;i<=pnt;i++){
tmp++;
if (i==pnt || lst[i]!=lst[i+1])
_q[tmp]++,tmp=0;
}
H[u]=ORI1;
for (int i=1;i<=pnt;i++) (((H[u]*=BASE1)+=lst[i])^=lst[i])+=lst[i];
((H[u]+=END1)*=END1)^=END1;
}else if (u!=rt){
int k;
for (int p=head[u];p;p=G[p].next)
if (V==fa) { k=p; break; }
for (int p=G[k].next;p;p=G[p].next)
lst[++pnt]=H[V];
for (int p=head[u];p!=k;p=G[p].next)
lst[++pnt]=H[V];
ull H1,H2;
H1=ORI2;
for (int i=1;i<=pnt;i++) (((H1*=BASE2)+=lst[i])^=lst[i])+=lst[i];
((H1+=END2)*=END2)^=END2;
H2=ORI2;
for (int i=pnt;i;i--) (((H2*=BASE2)+=lst[i])^=lst[i])+=lst[i];
((H2+=END2)*=END2)^=END2;
H[u]=min(H1,H2);
if (pnt>=2 && H1==H2)
_q[2]++;
}else{
for (int p=head[u];p;p=G[p].next)
if (V!=fa)
lst[++pnt]=H[V];
int ret=KMP(lst,pnt),t=ret;
for (int i=1;i<=num && prime[i]<=ret;i++)
while (t%prime[i]==0)
t/=prime[i],q[prime[i]]++;
}
}
namespace Cac{
struct edge{
int u,v,next;
}G[N<<1];
int head[N],inum=1;
inline void add(int u,int v){
int p=++inum; G[p].u=u; G[p].v=v; G[p].next=head[u]; head[u]=p;
}
set<abcd> Set;
inline void Add(int u,int v){
if (u>v) swap(u,v); if (!Set.count(abcd(u,v))) Set.insert(abcd(u,v)),add(u,v),add(v,u);
}
int pre[N],low[N],clk;
stack<int> sta;
inline void dfs(int u,int fa){
pre[u]=low[u]=++clk; sta.push(u);
for (int p=head[u];p;p=G[p].next)
if (p^fa^1)
if (!pre[V]){
dfs(V,p);
low[u]=min(low[u],low[V]);
if (low[V]>=pre[u]){
++bcc;
while (sta.top()!=u){
int t=sta.top(); sta.pop();
::add(n+bcc,t),::add(t,n+bcc);
if (t==V) break;
}
::add(n+bcc,u); ::add(u,n+bcc);
}
}else
low[u]=min(low[u],pre[V]);
}
inline void Read(){
int k,x,y;
read(m);
while (m--){
read(k); read(x);
for (int i=2;i<=k;i++)
read(y),Add(x,y),x=y;
}
dfs(1,0);
}
}
int main(){
freopen("cactus.in","r",stdin);
freopen("cactus.out","w",stdout);
read(n); Pre(n<<1);
Cac::Read();
Root(1,0);
dfs(rt,0);
Print(n<<1);
return 0;
}