[BZOJ 2799]POI 2012 Salaries

来源:互联网 发布:mac怎么玩免费的游戏 编辑:程序博客网 时间:2024/05/29 08:15

算出每个点取值的范围:1~maxx_i。把没用的点从小到大放在一个数组里,按照maxx_i顺序扫描。

如果当前maxx_i=k的仅有一个点,且在1~k中只有一个数可用,那么这个节点的值确定了。

如果maxx_i=k的节点数==在1~k中可用的数的数量,很明显之前的节点会把这些数占满,1~k中可用的数全置为不可用。

复杂度:O(n)

#include <cstdio>#include <cstring>#include <algorithm>using namespace std;const int Maxn=1000005;int node[Maxn],next[Maxn],a[Maxn],dig[Maxn];int z[Maxn],q[Maxn],sum[Maxn],p[Maxn],fa[Maxn];int n,i,j,tot,root,N,head,l,r,t,maxx[Maxn],id[Maxn];int read(){  char ch=getchar();  int ret=0;  while (ch<'0' || ch>'9') ch=getchar();  while (ch>='0' && ch<='9')    {ret=ret*10+ch-'0'; ch=getchar();}  return ret;}void add(int x,int y)  { node[++tot]=y; next[tot]=a[x]; a[x]=tot; }int gf(int x){  int xx=x, xxx;  while (xx!=fa[xx]) xx=fa[xx];  while (x!=xx) xxx=x, x=fa[x], fa[xxx]=xx;  return xx;}void bfs(){  for (q[l=r=1]=root;l<=r;l++)  for (i=a[q[l]];i;i=next[i])   q[++r]=node[i];  for (i=1;i<=n;i++){  if (maxx[ q[i] ]>0) continue;  //t = maxx[ q[i] ] =lower_bound( dig+1,dig+N+1,maxx[ p[q[i]] ]-1 )-dig;  t = maxx[ q[i] ] = gf( maxx[ p[q[i]] ]-1 );  //go[i]=tb[t]; tb[t]=i;  sum[t]++; if (sum[t]==1) id[t]=q[i];  }}int main(){  freopen("pen.in","r",stdin);  freopen("pen.out","w",stdout);  //scanf("%d",&n);  n=read();  for (i=1;i<=n;i++) fa[i]=i;  for (i=1;i<=n;i++){  //scanf("%d%d",&p[i],&z[i]);  p[i]=read(); z[i]=read();  if (i!=p[i]) add(p[i],i);    else root=i;  if (z[i]>0) maxx[i]=z[i], fa[z[i]]=z[i]-1;  }  z[root]=n; maxx[root]=n; fa[n]=n-1;  for (i=1;i<=n;i++)    if (fa[i]==i) dig[++N]=i;  bfs();  //for (i=1;i<=n;i++) printf("%d\n",maxx[i]);  //printf("\n");  for (i=1,j=head=1;i<=n&&head<=N;i++){  //printf("%d\n",j);  for (;j<=N&&dig[j]<=i;j++);  if (sum[i]==1 && j-head==1)    z[ id[i] ]=dig[j-1];  if (sum[i-1]+sum[i]==j-head)    head=j, sum[i]=0;  else sum[i]+=sum[i-1];  }  for (i=1;i<=n;i++) printf("%d\n",z[i]);  return 0;}


0 0
原创粉丝点击