【GDOI2017 day1】取石子游戏

来源:互联网 发布:mac 10.11.6 升级包 编辑:程序博客网 时间:2024/06/05 02:01

Description

题意简单一点:给出一棵树,让你求出每个节点的子树以外的mex(最小没出现过的自然数)

Solution

比赛的时候没有看懂,就没敢去打,其实思想很简单。
对于一个序列来说,包含一个x的区间答案肯定不是x。
那么我们把这个想法放到树上。
对于颜色x,我们提取出来,求出他们的lca(求lca是满足结合律的),假设这个lca为y,那么很显然的除了y这个子树,其他的子树都没有x这个颜色了。现在我们要求的是子树之外的mex,那么包含y这个子树的只有y到根路径上的节点。
那么我们现在从小到大枚举颜色,求出lca后,一个个往上跳,假如当前这个节点已经被标记过颜色了,那么就可以break掉,否则就标色。因为从小到大,肯定满足最小。

Code

#include<iostream>#include<stdio.h>#include<algorithm>#include<math.h>#include<string.h>#define fo(i,a,b) for(i=a;i<=b;i++)#define fod(i,a,b) for(i=a;i>=b;i--)#define rep(i,a) for(i=first[a];i;i=next[i])using namespace std;const int maxn=1e6+7;int i,j,k,l,t,n,m,ans,cas,x,y;int first[maxn],last[maxn],next[maxn],a[maxn],num;int f[maxn][21],deep[maxn];int bz[maxn],az[maxn],hou[maxn],an[maxn],du[maxn],d[maxn];int get(){    char ch=getchar();int x=0;    while(ch<'0'||ch>'9')ch=getchar();    while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();    return x;}void add(int x,int y){    last[++num]=y,next[num]=first[x],first[x]=num;}void bfs(){    int i,head=0,tail=0,x;    fo(i,1,n)if(!du[i])d[++tail]=i;deep[1]=1;    while(head<tail){        x=d[++head];        rep(i,x){            du[last[i]]--;if(!du[last[i]])d[++tail]=last[i];            f[last[i]][0]=x;deep[last[i]]=deep[x]+1;        }    }}int lca(int x,int y){    int i;if(deep[x]<deep[y])swap(x,y);    fod(i,20,0)if(deep[f[x][i]]>deep[y])x=f[x][i];    if(deep[x]!=deep[y])x=f[x][0];    fod(i,20,0)if(f[x][i]!=f[y][i])x=f[x][i],y=f[y][i];    if(x!=y)return f[x][0];return x;}int main(){    freopen("game.in","r",stdin);    freopen("game.out","w",stdout);    for(scanf("%d",&cas);cas;cas--){        num=0,memset(first,0,sizeof(first));memset(bz,0,sizeof(bz));        memset(an,255,sizeof(an));memset(du,0,sizeof(du));        scanf("%d%d",&n,&m);        fo(i,1,n)a[i]=get();        fod(i,n,1){            hou[i]=bz[a[i]];bz[a[i]]=i;        }        fo(i,1,n-1)k=get(),l=get(),add(k,l),du[l]++;        bfs();fo(j,1,20)fo(i,1,n)f[i][j]=f[f[i][j-1]][j-1];        fo(i,0,m){            x=bz[i];y=0;            if(!x){                fo(j,1,n)if(an[j]==-1)an[j]=i;break;            }            while(x){                if(!y)y=x;                else y=lca(y,x);                x=hou[x];            }            while(y&&an[y]==-1)an[y]=i,y=f[y][0];        }        fo(i,1,n){if(an[i]==-1)an[i]=0;printf("%d ",an[i]);}        printf("\n");    }}
1 0
原创粉丝点击