luogu P6086 【模板】Prufer 序列
阿新 • • 發佈:2021-06-17
題面傳送門
這個東西主要用於生成樹計數一類問題。
對於一個\(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); } }