• [loj3504]支配


    令$S_{x}$表示$x$支配的节点集合,可以暴力枚举$x$并求出$S_{x}$(删去$x$后从1开始dfs,复杂度为$o(nm)$),进而反过来即可求出受支配集$D_{x}$

    结论1:若$zin S_{x}cap S_{y}$,则有$xin S_{y}$或$yin S_{x}$

    由于$x$和$y$都支配$z$,那么考虑任意一条从1到$z$的简单路径,必然经过$x$和$y$(且恰好经过一次)

    考虑两者经过的先后顺序,不妨假设先经过$x$,那么若$x$不支配$y$,即存在从1到$y$且经过$x$的简单路径,再从$y$到$z$即可,那么即与$x$支配$z$矛盾,反之类似,即得证

    结论2(传递性):若$xin S_{y}$,则$S_{x}subset S_{y}$

    (关于这个结论比较显然,严格包含是因为$yin S_{y}$且$y otin S_{x}$)

    综合上述两个结论,任意两个集合要么成严格包含关系,要么不交,即可构成一棵树形关系

    更具体的,这棵树以1为根,且对于$xge 2$,令$x$的父亲$y$为满足$S_{x}subset S_{y}$且$|S_{y}|$最小(可以证明唯一)

    此时,对于一个节点$x$,其受支配集$D_{x}$即为其到根路径上所有节点

    关于这棵树的求法,(求出$S_{x}$和$D_{x}$后)有以下暴力$o(n^{2})$的做法——

    选择当前受支配集为空的节点$x$,对于所有$yin S_{x}$的节点在$D_{y}$中删除$x$,并且$x$的父亲即为$D_{x}$中最后一个被删除的节点,以下记作$fa_{x}$

    但暴力删除复杂度无法接受,直接记录$|D_{y}|$即可

    当然,还有更为优秀的$o(n)$的做法,可以自行搜索支配树

    求出支配树后,考虑询问插入$(x_{0},y_{0})$这条边时的情况——

    结论3:若$D_{x}$变化,则$x$子树内所有节点受支配集均发生变化

    由于是插入边$(x_{0},y_{0})$且初始1可以到达任意点,那么$D_{x}$变化必然是节点被删除

    假设删除的是$y$,对于$x$子树内的节点$z$,显然也可以构造出不经过$y$到达$z$的路径,因此$y$也在$D_{z}$中被删除

    由此,我们发现受支配集变化的一定是若干棵不交的子树,显然仅关心于子树的根,也即$D_{x}$发生变化但$D_{fa_{x}}$不发生变化的节点$x$

    结论4:$D_{x}$变化且$D_{fa_{x}}$未发生变化,必然有$fa_{x} otin D_{x}$(变化后的$D_{x}$)

    反证法,假设$fa_{x}in D_{x}$,那么$D_{x}$中被删除的节点$y$必然是$fa_{x}$的祖先(且不为$fa_{x}$自身),接下来对于从1到$x$且不经过$y$的路径,对其是否经过$fa_{x}$分类讨论——

    (1)若其经过$fa_{x}$,那么$y$不再支配$fa_{x}$,与$D_{fa_{x}}$未变化矛盾

    (2)若不经过$fa_{x}$,那么即存在从1到$x$且不经过$fa_{x}$的路径,与$fa_{x}in D_{x}$矛盾

    综上,即说明$fa_{x} otin D_{x}$

    同时,在满足这个条件时,$D_{x}$必然发生变化,因此只需要找出所有这样的$x$,并标记,之后再一次dfs统计所有到根路径上存在此类标记的节点即可

    下面,即查询所有节点$x$,满足存在一条路径使得其不经过$fa_{x}$到达$x$,若不经过新边$(x_{0},y_{0})$显然不存在此类路径,因此也即要求存在从1到$x_{0}$和从$y_{0}$到$x$的路径,且都不能经过$fa_{x}$

    同时,这两段都不能利用新边,那么第一个问题中也即要求$x_{0}$不能在$fa_{x}$的子树中,第二个问题对每一个$x$独立,也即对于原图的反图从$x$开始不经过$fa_{x}$能到达$y_{0}$

    两者都可以预处理出来,之后即可$o(1)$判断每一个节点$x$是否满足这两个条件,复杂度为$o(nq)$

    然而还是会被卡常, 因此还有下面复杂度更优秀的做法——

    更进一步的,将询问排序后考虑相同的$y_{0}$,其限制了若干个点,同时$x_{0}$又限制了其到根以及其所有儿子不能选,那么令$f_{k}$表示$k$子树内仅考虑$k$子树内权值的答案,维护其到根路径的答案即可

    时间复杂度降为$o(nm+q)$,可以轻松的通过

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 #define N 3005
     4 struct Edge{
     5     int nex,to;
     6 }edge[N<<2];
     7 queue<int>q;
     8 vector<int>v[N],S[N];
     9 int E,n,m,t,x,y,ans,head[2][N],vis[N],D[N],fa[N],dfn[N],sz[N],Vis[N][N];
    10 void add(int p,int x,int y){
    11     edge[E].nex=head[p][x];
    12     edge[E].to=y;
    13     head[p][x]=E++;
    14 }
    15 void dfs(int p,int k){
    16     if (vis[k])return;
    17     vis[k]=1;
    18     for(int i=head[p][k];i!=-1;i=edge[i].nex)dfs(p,edge[i].to);
    19 }
    20 void dfs(int k){
    21     dfn[k]=++dfn[0];
    22     sz[k]=1;
    23     for(int i=0;i<v[k].size();i++){
    24         dfs(v[k][i]);
    25         sz[k]+=sz[v[k][i]];
    26     }
    27 }
    28 void calc(int k,int p){
    29     if (vis[k])p=1;
    30     if (p)ans++;
    31     for(int i=0;i<v[k].size();i++)calc(v[k][i],p);
    32 }
    33 int main(){
    34     scanf("%d%d%d",&n,&m,&t);
    35     memset(head,-1,sizeof(head));
    36     for(int i=1;i<=m;i++){
    37         scanf("%d%d",&x,&y);
    38         add(0,x,y);
    39         add(1,y,x);
    40     }
    41     for(int i=1;i<=n;i++){
    42         memset(vis,0,sizeof(vis));
    43         vis[i]=1;
    44         dfs(0,1);
    45         for(int j=1;j<=n;j++)
    46             if (!vis[j]){
    47                 S[i].push_back(j);
    48                 D[j]++;
    49             }
    50     }
    51     q.push(1);
    52     while (!q.empty()){
    53         int k=q.front();
    54         q.pop();
    55         for(int i=0;i<S[k].size();i++){
    56             fa[S[k][i]]=k;
    57             if (--D[S[k][i]]==0)q.push(S[k][i]);
    58         }
    59     }
    60     for(int i=2;i<=n;i++)v[fa[i]].push_back(i);
    61     dfs(1);
    62     for(int i=2;i<=n;i++){
    63         memset(vis,0,sizeof(vis));
    64         vis[fa[i]]=1;
    65         dfs(1,i);
    66         vis[fa[i]]=0;
    67         memcpy(Vis[i],vis,sizeof(vis));
    68     }
    69     for(int i=1;i<=t;i++){
    70         scanf("%d%d",&x,&y);
    71         memset(vis,0,sizeof(vis));
    72         for(int j=2;j<=n;j++){
    73             if ((dfn[fa[j]]<=dfn[x])&&(dfn[x]<dfn[fa[j]]+sz[fa[j]]))continue;
    74             if (Vis[j][y])vis[j]=1;
    75         }
    76         ans=0;
    77         calc(1,0);
    78         printf("%d
    ",ans);
    79     }
    80 }
    View Code
  • 相关阅读:
    迅为iTOP4412开发板支持4G以上文件系统扩展
    迅为瑞芯微itop3399开发板Android8系统wifi移植
    centos 下安装显卡驱动步骤
    smarty函数转载
    jquery.qrcode二维码插件生成彩色二维码
    转 jquery插件241个jquery插件—jquery插件大全
    收集的jquery插件
    主机屋空间
    用过的php函数
    VeryMule网上商城
  • 原文地址:https://www.cnblogs.com/PYWBKTDA/p/14672425.html
Copyright © 2020-2023  润新知