AcWing 352. 闇の連鎖

原题链接

考察:LCA + 枚举

完全不会...LCA真难....

思路:

       很容易看出两个分为两段的方式:

  1. 附加边加上成环后,环上去掉一个树边和一个非树边.
  2. 未成环的树边去掉一个边,然后任意去掉一个非树边.

       设d[x] 表示 x点到其父节点的边上要去掉d[x]条非树边才断.

       考虑枚举非树边,对于非树边环上的每一个树边.都需要去掉一个树边才能断.因此环上树边d[x]+1.如何快速将环上所有边+1? 这就涉及了LCA.

 1 #include <iostream>
 2 #include <cstring>
 3 #include <queue>
 4 #include <algorithm>
 5 using namespace std;
 6 const int N = 100010,M = 200010;
 7 int h[N],idx,n,m,p[N],depth[N],fa[N][19],d[N];
 8 struct Road{
 9     int fr,to,ne;
10 }road[N<<1];
11 void add(int a,int b)
12 {
13     road[idx].fr = a,road[idx].to = b,road[idx].ne = h[a],h[a] = idx++;
14 }
15 void bfs(int s)
16 {
17     queue<int> q;
18     memset(depth,0x3f,sizeof depth);
19     depth[0] = 0,depth[s] = 1;
20     q.push(s);
21     while(q.size())
22     {
23         int u = q.front();
24         q.pop();
25         for(int i=h[u];~i;i=road[i].ne)
26         {
27             int v = road[i].to;
28             if(depth[v]>depth[u]+1)
29             {
30                 depth[v] =  depth[u]+1;
31                 q.push(v);
32                 fa[v][0] = u;
33                 for(int j=1;j<=17;j++)
34                   fa[v][j] = fa[fa[v][j-1]][j-1];
35             }
36         }
37     }
38 }
39 int lca(int a,int b)
40 {
41     if(depth[a]<depth[b]) swap(a,b);
42     for(int i=17;i>=0;i--)
43       if(depth[fa[a][i]]>=depth[b]) a = fa[a][i];
44     if(a==b) return a;
45     for(int i=17;i>=0;i--)
46       if(fa[a][i]!=fa[b][i]) a = fa[a][i],b = fa[b][i];
47     return a = fa[a][0];
48 }
49 int dfs(int u,int fa)
50 {
51     int res = 0;
52     for(int i=h[u];~i;i=road[i].ne)
53     {
54         int v = road[i].to;
55         if(v==fa) continue;
56         res+=dfs(v,u);
57         if(d[v]==1) res++;
58         else if(!d[v]) res+=m;
59         d[u]+=d[v];
60     }
61     return res;
62 }
63 int main()
64 {
65     scanf("%d%d",&n,&m);
66     memset(h,-1,sizeof h);
67     for(int i=1;i<n;i++)
68     {
69         int a,b; scanf("%d%d",&a,&b);
70         add(a,b); add(b,a);
71     }
72     bfs(1);
73     for(int i=1;i<=m;i++)
74     {
75         int a,b; scanf("%d%d",&a,&b);
76         d[a]+=1,d[b]+=1;
77         d[lca(a,b)]-=2;
78     }
79     printf("%d\n",dfs(1,-1));
80     return 0;
81 }

 

posted @ 2021-05-11 14:03  acmloser  阅读(40)  评论(0编辑  收藏  举报