luogu P6086 模板Prufer 序列
Posted 275307894a
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了luogu P6086 模板Prufer 序列相关的知识,希望对你有一定的参考价值。
题面传送门
这个东西主要用于生成树计数一类问题。
对于一个\\(n\\)个点的树,它的Prufer序列长度为\\(n-2\\)且这两者一一对应。
所以这个就很好解释了\\(n\\)个点生成树为\\(n^{n-2}\\)个。
一棵树转化成prufer序列是这样的:
找到一个编号最小的叶子节点,将这个叶子节点的父亲加入,并删除这个叶子节点,直到两个点停止。
这个东西指针随便维护一下就是\\(O(n)\\)的。
转回来是找到最小的叶子节点,然后将当前prufer点与这个点连一条边,并删除这个叶子节点。
这个也可以指针维护。
时间复杂度\\(O(n)\\)
code:
#include <vector>
#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#include<cmath>
#include<algorithm>
#include<bitset>
#include<set>
#include<map>
#define I inline
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
#define abs(x) ((x)>0?(x):-(x))
#define re register
#define ll long long
#define db double
#define N 5000000
#define M 1000
#define eps (1e-5)
#define mod (1<<31)
#define U unsigned int
using namespace std;
int n,m,A[N+5],F[N+5],in[N+5],B[N+5],Bh,now=1;ll Ans;
int main(){
freopen("1.in","r",stdin);
re int i;scanf("%d%d",&n,&m);
if(m==1){
for(i=1;i<n;i++) scanf("%d",&A[i]),in[A[i]]++;
while(Bh<n-2){
while(in[now])now++;B[++Bh]=A[now];//printf("%d\\n",Bh);
while(Bh<n-2&&!--in[B[Bh]]&&B[Bh]<now) B[Bh+1]=A[B[Bh]],Bh++;now++;
}
for(i=1;i<=n-2;i++) Ans^=1ll*i*B[i];printf("%lld\\n",Ans);
}
else{
for(i=1;i<n-1;i++) scanf("%d",&A[i]),in[A[i]]++;A[n-1]=n;
while(Bh<n-1){
while(in[now]) now++;B[now]=A[++Bh];
while(Bh<n-1&&!--in[A[Bh]]&&A[Bh]<now) B[A[Bh]]=A[Bh+1],Bh++;now++;
}
for(i=1;i<=n-1;i++) Ans^=1ll*i*B[i];printf("%lld\\n",Ans);
}
}
以上是关于luogu P6086 模板Prufer 序列的主要内容,如果未能解决你的问题,请参考以下文章