zoukankan      html  css  js  c++  java
  • BZOJ 2815 ZJOI2012 灾难

    2815: [ZJOI2012]灾难

    Time Limit: 10 Sec  Memory Limit: 128 MB
    Submit: 1518  Solved: 848
    [Submit][Status][Discuss]

    Description

     http://www.lydsy.com/JudgeOnline/upload/zjoi2012.pdf

    Input

    Output

    Sample Input

    Sample Output

    HINT

    Source

    题面好简陋啊QAQ

    抄自cydiater大神

    学LCA的时候根本没意识到LCA可以有这么多玩法。

    这玩意据说是个高级数据结构(支配树)的弱化版,蒟蒻没学过呀。所以出题人提出一个概念叫灾难树。


    我理解的灾难树的意思实际上是属于DAG的一个子图(我不知道怎么描述,就叫子图吧!)。灾难树关于DAG有这样一个性质。就是说在DAG上删掉某一点后,如果存在一个点的入度变为0.那么这个点就删去,以此类推,而被删去的点是这个所有被迫删除的点的父亲。

    上面实际上就是把题面描述了一遍QAQ。

    如何根据原DAG构建灾难树呢?

    首先把DAG拓扑排个序。然后逆序遍历,对于拓扑序上的每一个点。找到他所有子节点在新图上的LCA(如果不存在或者LCA就是该节点就设为0)。然后就在新图上由LCA向这个点连边。最后形成的新图就是灾难树。

    其实如果偏感性的理解的话,就是如果一个点所有出边所连接的点,或者通俗点说,就是所有食物都没了,那么这个点是一定要随之被删掉的。也就是说LCA的被删去必定会导致当前节点的被删去。

    #include <bits/stdc++.h>
    using namespace std;
    inline int read(){
     int x=0;int f=1;char ch=getchar();
     while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();}
     while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();}
     return x*f;
    }
    const int MAXN=700000;
    namespace zhangenming{
     struct node{
      int y;int next;
     }e[MAXN],E[MAXN];
     int linkk[MAXN],Linkk[MAXN],n,len=0,siz[MAXN]={},cnt[MAXN]={},fa[MAXN][22]={},q[MAXN];
     int dep[MAXN]={},head=0,tail=0;
     inline void insert(int xx,int yy){e[++len].y=yy;e[len].next=linkk[xx];linkk[xx]=len;}
     inline void Insert(int xx,int yy){E[++len].y=yy;E[len].next=Linkk[xx];Linkk[xx]=len;}
     void init(){
      n=read();
      for(int i=1;i<=n;i++){
        int yy=read();;
        while(yy){
        insert(i,yy);
        cnt[yy]++;
        yy=read();
       }
      }
     }
     void dfs(int node){
      for(int i=Linkk[node];i;i=E[i].next){
       dfs(E[i].y);
       siz[node]+=siz[E[i].y];
      }
      siz[node]+=1;
     }
     void getanser(int st){
      for(int i=1;i<=21;i++){
       if(fa[st][i-1]!=0) fa[st][i]=fa[fa[st][i-1]][i-1];
      }
     }
     int LCA(int xx,int yy){
      if(xx==-1) return yy;
      if(dep[xx]<dep[yy]) swap(xx,yy);
      for(int i=20;i>=0;i--){
       if(dep[xx]-(1<<i)>=dep[yy]) xx=fa[xx][i];
      }
      if(xx==yy) return xx;
      for(int i=20;i>=0;i--){
       if(fa[xx][i]!=fa[yy][i]&&fa[xx][i]!=0) {xx=fa[xx][i];yy=fa[yy][i];}
      }
      return fa[xx][0];
     }
     void solve(){
      for(int i=1;i<=n;i++){
       if(cnt[i]==0) q[++tail]=i;
      }
      while(head<tail){
       int tn=q[++head];
       for(int i=linkk[tn];i;i=e[i].next){
        if(--cnt[e[i].y]==0) {q[++tail]=e[i].y;dep[e[i].y]=dep[tn]+1;}
       }
      }
      for(int h=tail;h>0;h--){
       int lca=-1;int node=q[h];
       for(int i=linkk[node];i;i=e[i].next){lca=LCA(lca,e[i].y);}
       if(lca==node||lca==-1) lca=0;
       Insert(lca,node);fa[node][0]=lca;dep[node]=dep[lca]+1;
       getanser(node);
      }
      dfs(0);
     }
     void print(){
      for(int i=1;i<=n;i++){
       printf("%d
    ",siz[i]-1);
      }
     }
    }
    int main(){
     //freopen("a.in","r",stdin);
     //freopen("a.out","w",stdout);
     using namespace zhangenming;
     init();
     solve();
     print();
     return 0;
    }
    

      

  • 相关阅读:
    [转]在Ubuntu 下安装Redis 并使用init 脚本启动
    [资源]PHP使用消息队列
    [转]reids客户端 redis-cli用法
    [转]redis.conf的配置解析
    【转】微信公共号开发,提示“该公众号暂时无法提供服务,请稍后再试”,如何解决?
    [转]php 解决json_encode中文UNICODE转码问题
    [资料]Keychain 获取设备唯一
    [转]PHP 获取服务器详细信息代码
    crontab任务取消发送邮件
    [转]php返回json数据中文显示的问题
  • 原文地址:https://www.cnblogs.com/something-for-nothing/p/7906329.html
Copyright © 2011-2022 走看看