zoukankan      html  css  js  c++  java
  • 【LOJ 10131】暗的连锁

    题目描述:

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

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

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

    输入格式:

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

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

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

    输出格式:

    输出一个整数表示答案。

    输入样例

    4 1 
    1 2 
    2 3 
    1 4 
    3 4
    输出样例

    3

     题解:详见一本通p251。主要就是用到了树上差分算法啦。

     
    #include<cstdio>
    #include<iostream>
    #include<cmath>
    #include<cstring>
    #include<cstdlib>
    #include<algorithm>
    #include<queue>
    #include<bits/stdc++.h>
    using namespace std;
    const int N=100002;
    struct node{
        int next;
        int to;
    }e[N*4];
    int head[N],d[N],x,y;
    int f[N][22],cnt,ans[N];
    int n,m;
    void dfs_YCLL(int u,int fa){
        d[u]=d[fa]+1;
        for(int i=0;i<=19;i++)
            f[u][i+1]=f[f[u][i]][i];
        for(int i=head[u];i;i=e[i].next){
            int v=e[i].to;
            if(v==fa) continue;
            f[v][0]=u; dfs_YCLL(v,u);
        }
    }
    
    int lca(int x,int y){
        if(d[x]<d[y]) swap(x,y);
        for(int i=20;i>=0;i--){
            if(d[f[x][i]]>=d[y]) x=f[x][i];
            if(x==y) return x;
        }
        for(int i=20;i>=0;i--)
            if(f[x][i]!=f[y][i]) 
               { x=f[x][i]; y=f[y][i]; }
        return f[x][0];
    }
    void dfs(int x){
        for(int i=head[x];i;i=e[i].next){
            int v=e[i].to;
            if(v==f[x][0]) continue;
            dfs(v); ans[x]+=ans[v];
        }
    }
    void add(int x,int y){
        e[++cnt].to=y;
        e[cnt].next=head[x];
        head[x]=cnt;
    }
    int main(){
        freopen("10131.in","r",stdin);
        freopen("10131.out","w",stdout);
        scanf("%d %d",&n,&m);
        for(int i=1;i<n;i++){
            scanf("%d %d",&x,&y);
            add(x,y); add(y,x);
        }
        dfs_YCLL(1,0);
        for(int i=1;i<=m;i++){
            scanf("%d %d",&x,&y);
            ans[x]++; ans[y]++;
            int z=lca(x,y);
            ans[z]-=2;
        }
        dfs(1); int yc=0;
        for(int i=2;i<=n;i++){
            if(ans[i]==1) yc++;
            if(ans[i]==0) yc+=m;
        }     
        printf("%d
    ",yc);
        return 0;
    }
  • 相关阅读:
    P3478 [POI2008]STA-Station
    P2015 二叉苹果树
    P2014 选课 (树型背包模版)
    求树的每个子树的重心
    求树的直径
    Javascript--防抖与节流
    JavaScript中call和apply的区别
    解决谷歌浏览器“此Flash Player与您的地区不相容,请重新安装Flash”问题(最新版)
    matlab实验代码(总)
    表达式树
  • 原文地址:https://www.cnblogs.com/wuhu-JJJ/p/11842584.html
Copyright © 2011-2022 走看看