zoukankan      html  css  js  c++  java
  • 支配树模板

      考试的时候sb $n^3$ 建了个支配树。明明 $n^2$ 是个人都能想出来。

      这东西背个定理和模板就行了(反正我不会证)。

      

       

      每次先求出dfs序,把semi[i]设成dfn[i].我的semi中存的dfs编号.

      按dfs序从大到小求sdom,用并查集维护这每个点到当前根路径上semi最小的点,显然遍历一遍pre[i]就能求出semi[i].

      把i放到semi[i]的vector里。

      然后显然当前i这棵子树已经遍历完了,把fa[i]的vector中的元素提取出来算idom,清空vector.

      最后dfs序从小到大把idom[x]!=id[semi[x]]的x改为idom[idom[x]]。

      代码很丑。

      1 #include<iostream>
      2 #include<cstdio>
      3 #include<algorithm>
      4 #include<cstring>
      5 #include<bitset>
      6 #include<vector>
      7 #define N 2000005
      8 #define M 2000005
      9 #define ll long long
     10 using namespace std;
     11 int n,k,m;
     12 int head[N],ver[M],nxt[M],tot;
     13 void add(int a,int b)
     14 {
     15     tot++;nxt[tot]=head[a];head[a]=tot;ver[tot]=b;return ;
     16 }
     17 int map[N];
     18 bool ok[N];
     19 int head2[N],ver2[M],nxt2[M],tot2;
     20 void add2(int a,int b)
     21 {
     22     tot2++;nxt2[tot2]=head2[a];head2[a]=tot2;ver2[tot2]=b;return ;
     23 }
     24 bool v[N];
     25 int dfn[N],fa[N],z,id[N];
     26 int sdom[N],idom[N];
     27 // sdom dfs序 idom 真实编号 
     28 void dfs(int x,int now)
     29 {
     30     map[x]=1;dfn[x]=++z;id[z]=x;sdom[x]=z;
     31     for(int i=head[x];i;i=nxt[i])
     32     {
     33         if(!map[ver[i]])
     34         {
     35             fa[ver[i]]=x;
     36             dfs(ver[i],now);
     37         }
     38     }
     39     return ;
     40 }
     41 int dom[N];int ban[N];
     42 bool dffs(int x,int pp)
     43 {
     44     v[x]=1;
     45     for(int i=head[x];i;i=nxt[i])
     46     {
     47         if(ban[ver[i]]||v[ver[i]])continue;
     48         if(ver[i]==pp||dffs(ver[i],pp))return 1;
     49     }
     50     return 0;
     51 }
     52 int dep[N];
     53 bool pan(int x)
     54 {
     55     memset(v,0,sizeof(v));
     56     if(dffs(0,x))return 1;
     57     return 0;
     58 }
     59 ll ans;int size[N];
     60 void dfs2(int x)
     61 {
     62     v[x]=1;size[x]=1;
     63     for(int i=head2[x];i;i=nxt2[i])
     64     {
     65         dep[ver2[i]]=dep[x]+1;
     66         dfs2(ver2[i]);
     67         size[x]+=size[ver2[i]];
     68     }
     69     if(x!=0&&dep[x]==1)ans+=1LL*size[x]*(size[x]-1)/2;
     70     return ;
     71 }
     72 vector<int>pre[N],sub[N];
     73 int f[N],va[N];
     74 int find(int x)
     75 {
     76     if(x==f[x])return x;
     77     int nw=find(f[x]);
     78     if(sdom[va[f[x]]]<sdom[va[x]])va[x]=va[f[x]];
     79     return f[x]=nw;
     80 }
     81 int eval(int x)
     82 {
     83     find(x);
     84     return va[x];
     85 }
     86 void solve()
     87 {
     88     for(int i=1;i<=n;i++)f[i]=i,va[i]=i;
     89     for(int i=z;i>=2;i--)
     90     {
     91         int p=id[i];
     92         for(int j=0;j<pre[p].size();j++)
     93         {
     94             if(dfn[pre[p][j]])sdom[p]=min(sdom[p],sdom[eval(pre[p][j])]);
     95         }
     96         sub[id[sdom[p]]].push_back(p);
     97         f[p]=fa[p];
     98         for(int j=0;j<sub[fa[p]].size();j++)
     99         {
    100             int tmp=sub[fa[p]][j];
    101             if(sdom[eval(tmp)]==sdom[tmp])idom[tmp]=fa[p];
    102             else idom[tmp]=eval(tmp);
    103         }
    104         sub[fa[p]].clear();
    105     }
    106     int p;
    107     for(int i=2;i<=z;i++)
    108     {
    109         p=id[i];
    110         if(idom[p]!=id[sdom[p]])idom[p]=idom[idom[p]];
    111         add2(idom[p],p);
    112     }
    113     return ;
    114 }
    115 int main()
    116 {
    117     scanf("%d%d",&n,&k);
    118     for(int i=1;i<=k;i++)
    119     {
    120         int cnt,tmp;scanf("%d",&cnt);
    121         for(int j=1;j<=cnt;j++)
    122         {
    123             scanf("%d",&tmp);
    124             add(tmp,i);
    125             pre[i].push_back(tmp);
    126         }
    127     }
    128     for(int i=k+1;i<=n;i++)add(0,i),pre[i].push_back(0);
    129     dfs(0,0);
    130     int ans0=0;
    131     for(int i=1;i<=k;i++)
    132     {
    133         if(map[i])
    134         {
    135             ok[i]=1;
    136             continue;
    137         }
    138         if(!ok[i])ans0++;
    139     }
    140     printf("%d
    ",ans0);
    141     for(int i=1;i<=k;i++)
    142     {
    143         if(!ok[i])printf("%d ",i);
    144     }puts("");
    145     solve();
    146     memset(v,0,sizeof(v));
    147     dfs2(0);
    148     printf("%lld
    ",ans);
    149     return 0;
    150 }
  • 相关阅读:
    试题 历届试题 国王的烦恼
    试题 历届试题 九宫重排
    试题 历届试题 网络寻路
    试题 历届试题 危险系数
    试题 历届试题 横向打印二叉树
    试题 历届试题 幸运数
    试题 历届试题 大臣的旅费
    试题 历届试题 连号区间数
    Linux多进行之fork
    linux C语言getopt()函数的使用
  • 原文地址:https://www.cnblogs.com/ezyzy/p/6560086.html
Copyright © 2011-2022 走看看