• p2921 Trick or Treat on the Farm


    传送门

    题目

    每年万圣节,威斯康星的奶牛们都要打扮一番,出门在农场的N个牛棚里转 悠,来采集糖果.她们每走到一个未曾经过的牛棚,就会采集这个棚里的1颗糖果。农场不大,所以约翰要想尽法子让奶牛们得到快乐.他给每一个牛棚设置了一个“后继牛 棚”.牛棚i的后继牛棚是next_i 他告诉奶牛们,她们到了一个牛棚之后,只要再往后继牛棚走去, 就可以搜集到很多糖果.事实上这是一种有点欺骗意味的手段,来节约他的糖果.第i只奶牛从牛棚i开始她的旅程.请你计算,每一只奶牛可以采集到多少糖果.

    分析

    首先我们先进行Tarjan缩点,将每点权值赋为环中点数,意为走入这个环可获得的糖果数。因为只有一条出边,所以之后我们便进行dfs,从每一个点出发所获糖果数即为它自身权值+由它到达的点出发所能获得的糖果数。

    代码
    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<string>
    #include<algorithm>
    #include<cctype>
    #include<cmath>
    #include<cstdlib>
    #include<ctime>
    #include<queue>
    #include<vector>
    #include<set>
    #include<map>
    #include<stack>
    using namespace std;
    int vis[110000],size[110000],nxt[110000],ist[110000],dfn[110000],low[110000];
    int sum,cnt,belong[110000],nxt2[110000],all[110000];
    stack<int>a;
    inline void read(int &x){
          int f=1;x=0;
          char s=getchar();
          while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();}
          while(s>='0'&&s<='9'){x=x*10+(s-'0');s=getchar();}
          x*=f;
    }
    inline void tarjan(int x){
          dfn[x]=low[x]=++cnt;
          a.push(x);
          ist[x]=1;
          if(!dfn[nxt[x]]){
              tarjan(nxt[x]);
              low[x]=min(low[x],low[nxt[x]]);
          }else if(ist[nxt[x]]){
              low[x]=min(low[x],dfn[nxt[x]]);
          }
          if(dfn[x]==low[x]){
              sum++;
              while(1){
                  int u=a.top();
                  a.pop();
                  ist[u]=0;
                  belong[u]=sum;
                  all[sum]++;
                  if(u==x)break;
              }
          }
    }
    inline void go(int x){
          if(size[x])return;
          size[x]=all[x];
          vis[x]=1;
          if(!nxt2[x])return;
          go(nxt2[x]);
          size[x]+=size[nxt2[x]];
    }
    int main(){
          int n,m,i,j,k;
          read(n);
          for(i=1;i<=n;i++)read(nxt[i]);
          for(i=1;i<=n;i++)
             if(!dfn[i])tarjan(i);
          for(i=1;i<=n;i++)
             if(belong[i]!=belong[nxt[i]])nxt2[belong[i]]=belong[nxt[i]];
          for(i=1;i<=sum;i++)
             if(!vis[i])
               go(i);
          for(i=1;i<=n;i++)printf("%d ",size[belong[i]]);
          return 0;
    }

  • 相关阅读:
    1059 C语言竞赛
    1058 选择题
    1057 数零壹
    1056 组合数的和
    1055 集体照
    Mysql--分库分表
    Mysql--改表结构
    Mysql--开始阶段
    Mysql--常用语句
    Mysql--grant授权
  • 原文地址:https://www.cnblogs.com/yzxverygood/p/9123153.html
Copyright © 2020-2023  润新知