zoukankan      html  css  js  c++  java
  • poj3417(lca + 树形dp)

    题目链接: http://poj.org/problem?id=3417

    题意: 先给出一棵树, 再添加 m 条新边, 然后再删除其中一条新边和一条树枝, 问有多少中删除方法可以使新树分成两部分 .

    思路:  lca + 树形dp

    添加新边后必然形成环, 对于添加新边 (u, v), 形成的环为 u -> v -> lca(u, v) -> u . 用一个权值记录一下边被环覆盖的次数, 即给每个环上的所有边权值加一 .

    通过画图可以发现:

    对于权值为 0 的树枝, 删除后即能将树分成两部分, 即其能和任意一条新边组合成一个合法方案, 对答案贡献为 m;

    对于权值为 1 的树枝, 删除后, 只能再删除其对应的新边能将树分成两部分, 即对答案贡献为 1;

    对于权值为 2 的树枝, 其和任意新边组合都不能将树分成两部分, 即对答案贡献为 0;

    那么现在只需要求出每条树枝的权值即可, 对于这个问题可以通过树形 dp 解决, 用 dp[x] 表示节点 x 和其父亲节点组成的边的权值,

    如果直接暴力求权值的话时间复杂度为O(n^2), 对于比较大的数据肯定会 tle . 事实上这些新边增加后形成的环对于彼此的权值是不会有影响的, 那么可以先将所有新边标记一下, 然后从下往上遍历一次树即可计算出所有边的权值.

    具体操作为, 对于每条新边 (u, v), 先令 dp[u] += 1, dp[v] += 1, dp[lca] -= 2, 然后 dfs 回溯时将儿子节点的权值累加到父亲节点上即可. (dp[lca] - 2 是为了消除当前环对其上面的节点的影响, 这个过程和树状数组改段求点差不多) .

    代码:

      1 #include <iostream>
      2 #include <stdio.h>
      3 #include <string.h>
      4 using namespace std;
      5 
      6 const int MAXN = 1e5 + 10;
      7 
      8 struct node{
      9     int u, v, lca, next;
     10 }edge1[MAXN << 1], edge2[MAXN << 1];
     11 
     12 int pre[MAXN], vis[MAXN], dp[MAXN];
     13 int head1[MAXN], head2[MAXN], id1, id2;
     14 
     15 void init(void){
     16     memset(dp, 0, sizeof(dp));
     17     memset(vis, 0, sizeof(vis));
     18     memset(head1, -1, sizeof(head1));
     19     memset(head2, -1, sizeof(head2));
     20     id1 = id2 = 0;
     21 }
     22 
     23 void addedge1(int u, int v){
     24     edge1[id1].v = v;
     25     edge1[id1].next = head1[u];
     26     head1[u] = id1++;
     27 }
     28 
     29 void addedge2(int u, int v){
     30     edge2[id2].v = v;
     31     edge2[id2].next = head2[u];
     32     head2[u] = id2++;
     33 }
     34 
     35 int find(int x){
     36     return pre[x] == x ? x : pre[x] = find(pre[x]);
     37 }
     38 
     39 void jion(int x, int y){
     40     x = find(x);
     41     y = find(y);
     42     if(x != y) pre[x] = y;
     43 }
     44 
     45 void tarjan(int u){
     46     pre[u] = u;
     47     vis[u] = 1;
     48     for(int i = head1[u]; i != -1; i = edge1[i].next){
     49         int v = edge1[i].v;
     50         if(!vis[v]){
     51             tarjan(v);
     52             jion(v, u);
     53         }
     54     }
     55     for(int i = head2[u]; i != -1; i = edge2[i].next){
     56         int v = edge2[i].v;
     57         if(vis[v]) edge2[i].lca = edge2[i ^ 1].lca = find(v);
     58     }
     59 }
     60 
     61 void dfs(int x, int fa){
     62     for(int i = head1[x]; i != -1; i = edge1[i].next){
     63         int v = edge1[i].v;
     64         if(v != fa){
     65             dfs(v, x);
     66             dp[x] += dp[v];
     67         }
     68     }
     69 }
     70 
     71 int main(void){
     72     int n, m, x, y;
     73     while(~scanf("%d%d", &n, &m)){
     74         init();
     75         for(int i = 1; i < n; i++){
     76             scanf("%d%d", &x, &y);
     77             addedge1(x, y);
     78             addedge1(y, x);
     79         }
     80         for(int i = 0; i < m; i++){
     81             scanf("%d%d", &x, &y);
     82             addedge2(x, y);
     83             addedge2(y, x);
     84             dp[x] += 1;
     85             dp[y] += 1;
     86         }
     87         tarjan(1);
     88         for(int i = 0; i < m; i++){
     89             int cc = i << 1;
     90             int lca = edge2[cc].lca;
     91             dp[lca] -= 2;
     92         }
     93         dfs(1, 0);
     94         int ans = 0;
     95         for(int i = 2; i <= n; i++){
     96             if(dp[i] == 0) ans += m;
     97             else if(dp[i] == 1) ans += 1;
     98         }
     99         printf("%d
    ", ans);
    100     }
    101     return 0;
    102 }
    View Code
  • 相关阅读:
    (原创)分享一下最近搞的tiny210V2从nand启动支持(K9GAG08U0F).
    (转)uboot 与系统内核中 MTD分区的关系
    (转)mkimage制作linux内核映像 即uImage是怎么制作的
    ExtJs 一些属性备忘录
    CSS 元素选择器
    为什么匿名内部类参数必须为final类型
    Unbuntu 14.04 64位 搭建交叉编译环境
    eclipse调试运行
    Linux中cat命令的用法
    android之json
  • 原文地址:https://www.cnblogs.com/geloutingyu/p/7259138.html
Copyright © 2011-2022 走看看