正题
题目链接:https://gmoj.net/senior/#main/show/5097
题目大意
nnn个点的一棵树,每个节点有权值。对于每个点求树上所有权值去除掉他的子树的权值后的mexmexmex值。
解题思路
对于一个权值www,权值为www的所有点的LCALCALCA到根节点的路径上都不会包括www这个权值。
我们从小到大枚举权值,将这些路径上用www覆盖答案,覆盖过的位置不再覆盖,用一个并查集维护覆盖过的集合即可,并查集的头部指向集合中最顶部的节点即可。
时间复杂度O(nlogn)O(n\log n)O(nlogn)
codecodecode
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cctype>
using namespace std;
const int N=1e6+10;
struct node{int to,next;
}a[N<<1];
int T,n,m,tot,ls[N],w[N],siz[N],f[N],v[N];
int fa[N],son[N],top[N],dep[N],ans[N];
int read(){int x=0,f=1;char c=getchar();while(!isdigit(c)){if(c=='-')f=-f;c=getchar();}while(isdigit(c)){x=(x<<1)+(x<<3)+c-'0';c=getchar();}return x*f;
}
void print(int x)
{if(x>9)print(x/10);putchar(x%10+'0');return;}
void addl(int x,int y){a[++tot].to=y;a[tot].next=ls[x];ls[x]=tot;return;
}
void dfs1(int x){dep[x]=dep[fa[x]]+1;siz[x]=1;for(int i=ls[x];i;i=a[i].next){int y=a[i].to;if(y==fa[x])continue;fa[y]=x;dfs1(y);siz[x]+=siz[y];if(siz[y]>siz[son[x]])son[x]=y;}return;
}
void dfs2(int x){if(son[x]){top[son[x]]=top[x];dfs2(son[x]);}for(int i=ls[x];i;i=a[i].next){int y=a[i].to;if(y==fa[x]||y==son[x])continue;top[y]=y;dfs2(y);}return;
}
int LCA(int x,int y){while(top[x]!=top[y]){if(dep[top[x]]<dep[top[y]])swap(x,y);x=fa[top[x]];}return (dep[x]<dep[y])?x:y;
}
int find(int x)
{return (f[x]==x)?x:(f[x]=find(f[x]));}
int main()
{freopen("game.in","r",stdin);freopen("game.out","w",stdout);scanf("%d",&T);while(T--){n=read();m=read();tot=v[0]=0;for(int i=1;i<=n;i++){w[i]=read();f[i]=i;ls[i]=v[i]=ans[i]=son[i]=fa[i]=0;}for(int i=1;i<n;i++){int x=read(),y=read();addl(x,y);addl(y,x);}top[1]=1;dfs1(1);dfs2(1);for(int i=1;i<=n;i++){if(w[i]>n)continue;if(!v[w[i]])v[w[i]]=i;else v[w[i]]=LCA(v[w[i]],i);}int p=0;for(;v[p];p++){int x=find(v[p]);while(x){ans[x]=p+1;f[x]=fa[x];x=find(x);}}for(int i=1;i<=n;i++)print(ans[i]?(ans[i]-1):p),putchar(' ');putchar('\n');}return 0;
}