zoukankan      html  css  js  c++  java
  • poj3417 闇の連鎖 【树上差分】By cellur925

    闇の連鎖
    (yam.pas/c/cpp)
    题目描述
    传说中的暗之连锁被人们称为 DarkDark 是人类内心的
    黑暗的产物,古今中外的勇者们都试图打倒它。经过研究,
    你发现 Dark 呈现无向图的结构,图中有 N 个节点和两类边,
    一类边被称为主要边,而另一类被称为附加边。Dark N – 1
    条主要边,并且 Dark 的任意两个节点之间都存在一条只由主
    要边构成的路径。另外,Dark 还有 M 条附加边。
    你的任务是把 Dark 斩为不连通的两部分。一开始 Dark
    的附加边都处于无敌状态,你只能选择一条主要边切断。一
    旦你切断了一条主要边,Dark 就会进入防御模式,主要边会变为无敌的而附加边可以被切
    断。但是你的能力只能再切断 Dark 的一条附加边。现在你想要知道,一共有多少种方案可
    以击败 Dark。注意,就算你第一步切断主要边之后就已经把 Dark 斩为两截,你也需要切断
    一条附加边才算击败了 Dark
    输入格式
    第一行包含两个整数 N M
    之后 N – 1 行,每行包括两个整数 A B,表示 A B 之间有一条主要边。
    之后 M 行以同样的格式给出附加边。
    输出格式
    输出一个整数表示答案。

    显然,这个图上的点与主要边构成了一棵树。当加入一条附加边时,会构成环。如果我们第一次砍主要边的时候砍的是$x$->$y$路径上的某条边,那么之后再砍的附加边一定是$<x,y>$。

    这样,我们的题目就转换成了一个树上差分的问题。附加边$<x,y>$会影响x到y路径上的所有边。把这些边经过的次数(受影响的次数)进行统计。若第一次砍的是覆盖0次的,那么第二步可任意切断一条附加边;若一次砍的 是覆盖1次的,第二步方法唯一;其他答案在第二步均没有其他任何方法。

    实现的时候dfs和lca查询写错了两个细节,结果调了很久...气orz

    Code

     1 #include<cstdio>
     2 #include<algorithm>
     3 #include<queue>
     4 #include<cmath>
     5 #define maxn 100090
     6 
     7 using namespace std;
     8 
     9 int n,m,tot,t,ans;
    10 int head[maxn],d[maxn],f[maxn][30],val[maxn];
    11 struct node{
    12     int to,next;
    13 }edge[maxn*2];
    14 
    15 void add(int x,int y)
    16 {
    17     edge[++tot].to=y;
    18     edge[tot].next=head[x];
    19     head[x]=tot;
    20 }
    21 
    22 void init()
    23 {
    24     queue<int>q;
    25     q.push(1),d[1]=1;
    26     while(!q.empty())
    27     {
    28         int u=q.front();q.pop();
    29         for(int i=head[u];i;i=edge[i].next)
    30         {
    31             int v=edge[i].to;
    32             if(d[v]) continue;
    33             d[v]=d[u]+1;
    34             f[v][0]=u;
    35             for(int j=1;j<=t;j++)
    36                 f[v][j]=f[f[v][j-1]][j-1];
    37             q.push(v);
    38         }
    39     } 
    40 }
    41 
    42 int lca(int x,int y)
    43 {
    44     if(d[x]>d[y]) swap(x,y);
    45     for(int i=t;i>=0;i--)
    46         if(d[f[y][i]]>=d[x]) y=f[y][i];
    47     if(x==y) return x;
    48     for(int i=t;i>=0;i--)
    49         if(f[x][i]!=f[y][i]) x=f[x][i],y=f[y][i];
    50     return f[x][0];
    51 } 
    52 
    53 void review(int u,int fa)
    54 {
    55     for(int i=head[u];i;i=edge[i].next)
    56     {
    57         int v=edge[i].to;
    58         if(v==fa) continue;
    59         review(v,u);
    60         val[u]+=val[v];
    61     }
    62 }
    63 
    64 int main()
    65 {
    66     scanf("%d%d",&n,&m);
    67     t=log2(n)+1;
    68     for(int i=1;i<=n-1;i++)
    69     {
    70         int x=0,y=0;
    71         scanf("%d%d",&x,&y);
    72         add(x,y);add(y,x);
    73     }
    74     init();
    75     for(int i=1;i<=m;i++)
    76     {
    77         int x=0,y=0;
    78         scanf("%d%d",&x,&y);
    79         int fa=lca(x,y);
    80         val[x]++,val[y]++;
    81         val[fa]-=2;
    82     }
    83     review(1,0);
    84     for(int i=2;i<=n;i++)
    85     {
    86         if(val[i]==0) ans+=m;
    87         else if(val[i]==1) ans++;
    88     }
    89     printf("%d
    ",ans);
    90     return 0;
    91 }
    View Code
  • 相关阅读:
    一个滑动小块
    js 封装的函数 总结
    引用公用文件
    静态页面表单中js验证
    linux中Firefox浏览器 手动安装 flash
    将双击“root的主文件”弹出的窗口设置为文件浏览器
    eclipse中的aptana插件的安装
    System Center VMM请注意不同语言版本的差异
    CodeFirst模式开发涉及到mysql简单使用
    Echarts的使用
  • 原文地址:https://www.cnblogs.com/nopartyfoucaodong/p/9726823.html
Copyright © 2011-2022 走看看