zoukankan      html  css  js  c++  java
  • LOJ10131暗的连锁

    题目描述

    原题来自:POJ 3417

    Dark 是一张无向图,图中有 N 个节点和两类边,一类边被称为主要边,而另一类被称为附加边。Dark 有 N–1 条主要边,并且 Dark 的任意两个节点之间都存在一条只由主要边构成的路径。另外,Dark 还有 M 条附加边。

    你的任务是把 Dark 斩为不连通的两部分。一开始 Dark 的附加边都处于无敌状态,你只能选择一条主要边切断。一旦你切断了一条主要边,Dark 就会进入防御模式,主要边会变为无敌的而附加边可以被切断。但是你的能力只能再切断 Dark 的一条附加边。

    现在你想要知道,一共有多少种方案可以击败 Dark。注意,就算你第一步切断主要边之后就已经把 Dark 斩为两截,你也需要切断一条附加边才算击败了 Dark。

    输入格式

    第一行包含两个整数 N 和 M

    之后 N – 1 行,每行包括两个整数 A 和 B,表示 A 和 B 之间有一条主要边;

    之后 M 行以同样的格式给出附加边。

    输出格式

    输出一个整数表示答案。

    样例

    样例输入

    4 1 
    1 2 
    2 3 
    1 4 
    3 4

    样例输出

    3

    数据范围与提示

    对于 20% 的数据,1N,M100;

    对于 100% 的数据,1N10^5,1M2×10^5。数据保证答案不超过 2^311。

    _______________________________________________________________________________________

    每一条非树边,都对应这一条树上的链,那么砍断这条非数遍后对应链上的数遍砍断就可以把图分成两半。

    但是两条非树边对应的链可能有重合,这样砍断重合的边,图就不能分成两半。

    所以对于每条非树边,要统计对应的树链上的各个边的重叠次数。这就用到了树上查分。

    所以,树边的重叠次数为1是,答案加一,表示砍断树边后有一条非树边与之对应,可以破开环,使图成为两半。

    如果重叠次数为2及以上,说明砍断该树边,还有两条及以上的非树边相连,不能把图分成两半,答案不变。

    如果重叠次数为0,说明该树边不在环上,切断它直接可以把图分成两半,所以非树边可以任意选,答案加M.

    _______________________________________________________________________________________

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 const int maxn=1e5+10;
     4 int n,m;
     5 struct edge
     6 {
     7     int u,v,nxt;
     8 }e[maxn<<1];
     9 int head[maxn],js;
    10 int dep[maxn],val[maxn];
    11 int f[maxn][20];
    12 long long ans;
    13 void addage(int u,int v)
    14 {
    15     e[++js].u=u;e[js].v=v;
    16     e[js].nxt=head[u];head[u]=js;
    17 }
    18 void dfs(int u,int fa)
    19 {
    20     dep[u]=dep[fa]+1;
    21     f[u][0]=fa;
    22     for(int i=1;i<20;++i)f[u][i]=f[f[u][i-1]][i-1];
    23     for(int i=head[u];i;i=e[i].nxt)
    24     {
    25         int v=e[i].v;
    26         if(fa!=v)dfs(v,u);
    27     }
    28 }
    29 int lca(int u,int v)
    30 {
    31     if(dep[u]<dep[v])swap(u,v);
    32     for(int i=19;i>=0;--i)if(dep[f[u][i]]>=dep[v])u=f[u][i];
    33     if(u==v)return u;
    34     for(int i=19;i>=0;--i)if(f[u][i]!=f[v][i])u=f[u][i],v=f[v][i];
    35     return f[u][0];
    36 }
    37 void dfsf(int u,int fa)
    38 {
    39     for(int i=head[u];i;i=e[i].nxt)
    40     {
    41         int v=e[i].v;
    42         if(v!=fa)
    43         {
    44             dfsf(v,u);
    45             val[u]+=val[v];
    46         }
    47     }
    48     if(val[u]==0 && u!=1)ans+=m;
    49     else if(val[u]==1)ans++;
    50 }
    51 int main()
    52 {
    53     scanf("%d%d",&n,&m);
    54     for(int u,v,i=1;i<n;++i)
    55     {
    56         scanf("%d%d",&u,&v);
    57         addage(u,v);addage(v,u);
    58     }
    59     dfs(1,0);
    60     for(int u,v,i=0;i<m;++i)
    61     {
    62         scanf("%d%d",&u,&v);
    63         int l=lca(u,v);
    64         ++val[u];++val[v];
    65         val[l]-=2;
    66     }
    67     dfsf(1,0);
    68     cout<<ans;
    69     return 0;
    70 }
    View Code

     

  • 相关阅读:
    对JavaScript调用堆栈和setTimeout用法的深入研究
    Js中的window.parent ,window.top,window.self 代表的对象
    lhgselect 联动选择下拉菜单 v1.0.0 (20110613)
    lhgcore JavaScript Library v1.4.5 API (20110622)
    表单元素完美垂直居中
    判断 iframe 是否加载完成的完美方法
    lhgdialog 弹出窗口插件 v3.5.2 ( 20110704 )
    JS的事件冒泡和事件捕获
    程序设计原则
    python中入口函数的用法
  • 原文地址:https://www.cnblogs.com/gryzy/p/10355520.html
Copyright © 2011-2022 走看看