• LOJ 暗的连锁 (POJ3417)【LCA + 树上差分 + 计数】


    LOJ 暗的连锁

    蛮不错的题。。。

    题目大意:先切一条主要边,再切一条附加边,使得图不连通的方案数。

    首先抓住一个要点:两个点之间加了一条附加边,等价于两点的唯一路径上所有点之间有两条路可互达。

    这是一条非常重要的性质。这样我们就可以利用 LCA (这里我用倍增,你们用 RMQ 也行)求出每条边被覆盖了几次。

    这里又用到了另一个技巧:树上差分

    具体的话:搜博客吧。。。

    和线性差分思想一样,求子树的值 + 自身的值,即为该节点的值。

    修改的时候:c[u]++, c[v]++, c[lca(u,v)]-=2 (至于为什么是这样,画画图,理解理解)

    1、若一次都未被覆盖,则切断这条边一定成立,则它可以和任意一条附加边 (m条) 成为组合,即对答案的贡献为 m 。

    2、若覆盖了一次,那么只有唯一的一种解就是把这条边切两遍,即对答案的贡献为 1 。

    3、其余的情况均不成立,即对答案无贡献。

    贴代码:

     1 #include<bits/stdc++.h>
     2 #define ll long long
     3 using namespace std;
     4 const int N=1e5+5;
     5 int n,m,nxt[N*2],to[N*2],hea[N],tot,c[N],f[N][25],dep[N],num[N];
     6 bool vis[N];
     7 ll ans;
     8 inline int read()
     9 {
    10     int x=0,f=1; char ch=getchar();
    11     while (!isdigit(ch)) f=(ch=='-')?-f:f,ch=getchar();
    12     while (isdigit(ch)) x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
    13     return x*f;
    14 }
    15 inline void add(int x,int y)
    16 {
    17     to[++tot]=y; nxt[tot]=hea[x]; hea[x]=tot;
    18 }
    19 inline void dfs(int x,int d,int fa)
    20 {
    21     for (int i=hea[x]; i; i=nxt[i])
    22     {
    23         int y=to[i];
    24         if (y==fa || dep[y]) continue;
    25         f[y][0]=x; dep[y]=d+1; dfs(y,d+1,x);
    26     }
    27 }
    28 inline int lca(int x,int y)
    29 {
    30     if (dep[x]<dep[y]) swap(x,y);
    31     for (int i=20; ~i; --i) if (dep[f[x][i]]>=dep[y]) x=f[x][i];
    32     if (x==y) return x;
    33     for (int i=20; ~i; --i)
    34       if (f[x][i]!=f[y][i]) x=f[x][i],y=f[y][i];
    35     return f[x][0];
    36 }
    37 inline int dfs1(int x)
    38 {
    39     vis[x]=1; num[x]=c[x];
    40     for (int i=hea[x]; i; i=nxt[i])
    41     {
    42         int y=to[i];
    43         if (vis[y]) continue;
    44         num[x]+=dfs1(y);
    45     }
    46     return num[x];
    47 }
    48 int main()
    49 {
    50     n=read(),m=read();
    51     register int u,v;
    52     for (int i=1; i<n; ++i)
    53     {
    54         u=read(),v=read();
    55         add(u,v); add(v,u);
    56     }
    57     dfs(1,0,0);
    58     for (int i=1; i<=20; ++i)
    59       for (int j=1; j<=n; ++j)
    60         f[j][i]=f[f[j][i-1]][i-1];
    61     for (int i=1; i<=m; ++i)
    62     {
    63         u=read(),v=read();
    64         c[u]++; c[v]++; c[lca(u,v)]-=2;
    65     }
    66     dfs1(1); ans=0;
    67     for (int i=1; i<=n; ++i)
    68     {
    69         if (num[i]==0 && i!=1) ans+=m;
    70         else if (num[i]==1) ans++;
    71     }
    72     printf("%lld
    ",ans);
    73     return 0;
    74 }
    View Code

    fighting fighting fighting

  • 相关阅读:
    Kubernetes service资源-十
    Kubernetes pod控制器应用-(六-九)
    Kubernetes资源清单定义入门-五
    centos下安装confluence
    安装mysql
    linux下安装mysql 5.7版本
    mybatis高效率批量update
    CentOS虚拟机断电或强制关机,再开机出现问题:Entering emergency mode. Exit the shell to continue.
    容易发生内存泄露
    springAOP实现方法运行时间统计
  • 原文地址:https://www.cnblogs.com/Frank-King/p/9832660.html
Copyright © 2020-2023  润新知