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

    题链

    我们考虑拓扑排序,那么我们可以构造一个树结构,使其满足:

    当一个点灭亡,其子树也灭亡。

    我们考虑对一个点的所有边求lca,把这个点加到lca的子树里就好了。

    答案就是子树的大小-1(减掉自己)

    #include<bits/stdc++.h>
    #define eho(X,x) for(int i=X.head[x];i;i=X.net[i])
    #define sight(c) ('0'<=c&&c<='9')
    #define pc printf
    using namespace std;
    #define N 100007
    inline void read(int &x){
        static char c;
        for (c=getchar();!sight(c);c=getchar());
        for (x=0;sight(c);c=getchar()) x=x*10+c-48;
    }
    int v,n,t,dep[N],to[N],q[N],be,tog,f[N][21],LA,siz[N];
    struct G{
        int fall[N<<1],head[N],net[N],tot;
        inline void add(int x,int y){
            fall[++tot]=y; net[tot]=head[x]; head[x]=tot;
        }
    }G1,G2,G3;
    int lca(int x,int y){
        if (dep[x]<dep[y]) swap(x,y);
        for (int i=18;~i;i--) if (dep[f[x][i]]>=dep[y]) x=f[x][i];
        if (x==y) return x;
        for (int i=18;~i;i--) if (f[x][i]^f[y][i]) x=f[x][i],y=f[y][i];
        return f[x][0];
    }
    void dfs(int x){
        siz[x]=1;
        eho(G2,x) dfs(G2.fall[i]),siz[x]+=siz[G2.fall[i]];
    }
    void write(int x){if (x<10){putchar(48+x);return;}write(x/10);putchar(48+x%10);}
    inline void writeln(int x){if (x<0) putchar('-'),x=-x; write(x); putchar('
    ');}
    int main () {
    //  freopen("a.in","r",stdin);
        read(n);
        for (int i=1;i<=n;i++) 
            while (read(t),t) 
              G1.add(t,i),G3.add(i,t),to[i]++; 
        for (int i=1;i<=n;i++)
          if (!to[i]) q[++tog]=i;
    //  cerr<<"rrsb"<<endl;
        while (tog<n) {
            ++be;
            eho(G1,q[be])  { 
            to[G1.fall[i]]--;
            if (!to[G1.fall[i]]) q[++tog]=G1.fall[i];}
        } 
    //  cerr<<"rrsb"<<endl;
        for (int t=1;t<=n;t++) {
            v=q[t]; 
            if (!G3.head[v]) {G2.add(0,v); dep[v]=1;continue;}
            else {LA=G3.fall[G3.head[v]];}
            eho(G3,v) LA=lca(LA,G3.fall[i]);
            G2.add(LA,v);  f[v][0]=LA; dep[v]=dep[LA]+1;
            for(int i=1;i<=18;i++) f[v][i]=f[f[v][i-1]][i-1];
        }
        dfs(0);
        for (int i=1;i<=n;i++) writeln(siz[i]-1);
        return 0;
    }
  • 相关阅读:
    【题解】警位安排( 树形 DP)
    【题解】任务分配
    Leo 搭积木
    受牛仰慕的牛
    zy 送画
    [NOIP2010] 乌龟棋
    [WikiOi 1214] 线段覆盖
    【拓扑习题】课程安排问题
    [WikiOI "天梯"1281] Xn数列
    [百度之星2014资格赛] Disk Schedule 报告
  • 原文地址:https://www.cnblogs.com/rrsb/p/8367226.html
Copyright © 2011-2022 走看看