Prüfer 序列
P6086 【模板】Prüfer 序列
还是 Prufer 序列好打一点。
这个东西是指对于有标号无根树,我们可以通过一个长度为 \(n-2\) 的序列唯一确定这棵无根树的形态,同时也可以在知道这棵树的形态的情况下求得 Purfer 序列。
这道模板题分为 Prufer 序列的构造与反推树形态两部分。
其是这样构造的:
每次选出还没被删掉的编号最小的叶子节点,然后将这个叶子的父亲插入 Prufer 序列的尾部,然后将这个叶子删掉,以此往复直到树中只剩下 2 个点。
这个过程我们可以通过一个单增的指针来维护。这个指针代表当前编号最小的叶子节点。如果我们删去了一个点,其父亲变成了一个新的叶子我们就要考虑其是否可以马上加入 Prufer 序列。如果这个父亲的编号比指针小,那么其一定就是最小的叶子了,直接加入即可。如果不是,那么显然其就不是最大的叶子,直接不管。反正指针是单增的一定可以遍历到这个点。
然后是反着构造树。考虑这样一个过程:
同样设立一个指针从小到大枚举点,然后从左向右遍历 Prufer 序列。如果指针已经在 Prufer 序列中被删完了(也就是说其不再是剩下的点的祖先了),那么指针的父亲就是当前遍历到的 Prufer 序列中的这个点,然后就可以将 Prufer 序列中的这个值删掉了。然后如果恰好也删完了,那么与上面类似的操作即可。
唯一性的话注意到通过 Prufer 序列构造树的唯一性是比较显然的,然后这个等价于树的形态与 Prufer 序列一一对应。
code
代码写的及其丑陋。自作多情的写了一个链表然后发现这个链表跟没有一样,u=nxt[u] 等价于 u++。然后代码写的也比较混乱,将就看一下。
点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define ll long long
#define gc getchar
int rd() {
	int x = 0, f = 1; char c = gc();
	while(c < '0' || c > '9') { if(c == '-') f = (- 1); c = gc(); }
	while(c >= '0' && c <= '9') { x = x * 10 + (c - '0'); c = gc(); }
	return (x * f);
}
void write(ll x) {
  static ll sta[35];
  ll top = 0;
  do {
    sta[top++] = x % 10ll, x /= 10ll;
  } while (x);
  while (top) putchar(sta[--top] + 48);  // 48 是 '0'
}
const int N=5e6+7;
int p[N],n,m,lst[N],nxt[N],a[N],du[N];
void del(int u){nxt[lst[u]]=nxt[u],lst[nxt[u]]=lst[u];}
namespace en_pufer{
	void calc(){
		for(int i=1;i<=n-m;i++)du[p[i]]++;
		int cnt=0,u=1;while(cnt<=n-2){
			if(!du[u]){
				a[++cnt]=p[u],del(u),du[p[u]]--;
				int now=p[u];
				while(!du[now]&&now<u){a[++cnt]=p[now],del(now),du[p[now]]--;now=p[now];}
			}
			u=nxt[u];
		}
	}
}
namespace de_pufer{
	void calc(){
		for(int i=1;i<=n-m;i++)du[p[i]]++;
		int u=1;
		for(int i=1;i<=n-m;i++){
			while(du[u])u=nxt[u];
			a[u]=p[i];del(u);
			while(i<n&&!--du[p[i]]&&p[i]<u)a[p[i]]=p[i+1],i++;
			u=nxt[u];
		}
		for(int i=1;i<n;i++)if(!a[i]){a[i]=n;break;}
	}
}
int get(){
	ll ans=0;for(int i=1;i<=n-(m^3);i++)ans^=1ll*i*a[i];
	return ans;
}
signed main(){
	n=rd(),m=rd();for(int i=1;i<=n-m;i++)p[i]=rd();for(int i=1;i<=n;i++)lst[i]=i-1,nxt[i]=i+1;nxt[0]=1;
	if(m==1)en_pufer::calc();else de_pufer::calc();write(get());
	return 0;
}
                    
                
                
            
        
浙公网安备 33010602011771号