POJ - 3417 Network (LCA+树上差分)

题目传送门:POJ - 3417 Network

题目大意:

存在一棵n个结点的树,加入m条新边,现在要让这个图不连通,你可以切断两条边,要求切断一条原边,一条新边,求切割的方案数。

分析:

加入m条新边,假设加入新边(u,v),那么u-->lca(u,v)-->v-->u形成一个环,此时可以切断新边,和环上任意的一条原边就可以使图不连通。

可以发现若加入一条新边,给环上的计数1,表示该边被一个环覆盖,树上有些边会被多个环覆盖,此时可以分情况讨论。

1、若该边被覆盖次数是0,则断掉该边后图已经满足不连通条件了,此时可以断掉任意一条新边,图依旧不连通,可该边以产生m种新方案。

2、若该边被覆盖次数是1,则断掉该边后必须断掉与之对应的新边才能使图不连通,可以产生1种新方案。

3、若该边被覆盖次数大于等于2,则不能在断掉一条新边和一条原边的情况下使图不连通,所以不能产生新方案。

所以该题目可以转化为,每次加入新边后,给形成对应的环上的边+1,最后统计树上所有边的权值(树上差分),若权值是0方案数+m,权值是1方案数+1

可以求出最后结果

代码

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int MAX=100009;
const int M=20;
int n,m,a,b;
int head[MAX],cnt=0;
int up[MAX][M];
int deep[MAX];
int de[MAX];
struct edge{
    int next,to;
}edge[MAX*2];
inline void add(int u,int v)
{
    edge[cnt].to=v;
    edge[cnt].next=head[u];
    head[u]=cnt++;
}
void dfs(int u)                                                    //遍历数,求出结点的深度和父亲
{
    for(int i=head[u];i!=-1;i=edge[i].next)
    {
        int to=edge[i].to;
        if(to==up[u][0])continue;
        deep[to]=deep[u]+1;
        up[to][0]=u;
        dfs(to);
    }
}
void init()
{
    memset(up,-1,sizeof(up));
    deep[1]=1;
    dfs(1);
    for(int j=1;(1<<j)<=n;j++)                                    //倍增
        for(int i=1;i<=n;i++)
            if(~up[i][j-1])
                up[i][j]=up[up[i][j-1]][j-1];
}
int lca(int a,int b)
{
    if(deep[a]<deep[b])
        swap(a,b);
    int d=deep[a]-deep[b];
    for(int i=0;i<M;i++)
        if(d&(1<<i))
            a=up[a][i];
    if(a==b)return a;
    for(int i=M-1;i>=0;i--)
    {
        if(up[a][i]!=up[b][i])
            a=up[a][i],b=up[b][i];
    }
    return up[a][0];
}
void dfs_ans(int u)
{
    for(int i=head[u];i!=-1;i=edge[i].next)
    {
        int to=edge[i].to;
        if(to==up[u][0])break;
        dfs_ans(to);
        de[u]=de[u]+de[to];
    }
}
int main()
{
    memset(head,-1,sizeof(head));
    memset(de,0,sizeof(de));
    scanf("%d%d",&n,&m);
    for(int i=1;i<n;i++)
    {
        scanf("%d%d",&a,&b);
        add(a,b);
        add(b,a);
    }
    init();
    for(int i=0;i<m;i++)
    {
        scanf("%d%d",&a,&b);
        de[a]++;                                //树上差分
        de[b]++;
        de[lca(a,b)]-=2;
    }
    dfs_ans(1);
    int res=0;
    for(int i=2;i<=n;i++)
    {
        if(de[i]==0)
            res+=m;
        if(de[i]==1)
            res++;
    }
    printf("%d\n",res);
    return 0;
} 

原文地址:https://www.cnblogs.com/LjwCarrot/p/9738045.html

时间: 2024-10-10 08:55:28

POJ - 3417 Network (LCA+树上差分)的相关文章

POJ - 3417 Network(LCA + DP)

题目大意:给出一棵N个结点的无根树,现在要在上面加上M条边,问,有多少种破坏方式(破坏一条树边,一条新边),能使这张新图变成至少两部分 解题思路:首先,假设添加的边为(u,v),那么u – > lca(u,v) –> v – >u就形成了一个环了,也就是说,每条添加的边都会在树上形成一个环 本来树上的每条边都是一条桥的,由于加了新的边了,形成了连通分量了,使得边的性质发生了些变化 首先,树边在0个连通分量里面的,那表示该树边还是桥,破坏了它,图肯定能分成两个部分,所以破坏方式就有M种了

Network POJ - 3417(LCA+dfs)

Yixght is a manager of the company called SzqNetwork(SN). Now she's very worried because she has just received a bad news which denotes that DxtNetwork(DN), the SN's business rival, intents to attack the network of SN. More unfortunately, the origina

NOIp2015 运输计划 [LCA] [树上差分] [二分答案]

我太懒了 吃掉了题面 题解 & 吐槽 一道很好的树上差分练习题. 不加fread勉强a过bzoj和luogu的数据,加了fread才能在uoj里卡过去. 可以发现,答案则是运输计划里花费的最大值,最大值最小,便是二分答案的标志. 那么该怎么check呢... 我们得找出所有超过限制的计划,这个过程可以在LCA倍增的过程中预处理出来. 然后再找出一些被这些计划都覆盖的边,找到最大的那条边,如果最大的计划花费减去最大的那条边小于x,那么x就是可行的. 但是该怎么找到那些被计划都覆盖的边呢... 我们

【洛谷】【lca+树上差分】P3258 [JLOI2014]松鼠的新家

[题目描述:] 松鼠的新家是一棵树,前几天刚刚装修了新家,新家有n(2 ≤ n ≤ 300000)个房间,并且有n-1根树枝连接,每个房间都可以相互到达,且俩个房间之间的路线都是唯一的.天哪,他居然真的住在”树“上. 松鼠想邀请小熊维尼前来参观,并且还指定一份参观指南,他希望维尼能够按照他的指南顺序,先去a1,再去a2,......,最后到an,去参观新家.可是这样会导致维尼重复走很多房间,懒惰的维尼不停地推辞.可是松鼠告诉他,每走到一个房间,他就可以从房间拿一块糖果吃. 维尼是个馋家伙,立马就

P2680 运输计划[二分+LCA+树上差分]

题目描述 公元20442044 年,人类进入了宇宙纪元. L 国有 nn 个星球,还有 n-1n?1 条双向航道,每条航道建立在两个星球之间,这 n-1n?1 条航道连通了 LL 国的所有星球. 小 P 掌管一家物流公司, 该公司有很多个运输计划,每个运输计划形如:有一艘物流飞船需要从 u_i*u**i* 号星球沿最快的宇航路径飞行到 v_i*v**i* 号星球去.显然,飞船驶过一条航道是需要时间的,对于航道 jj,任意飞船驶过它所花费的时间为 t_j*t**j*,并且任意两艘飞船之间不会产生任

习题:电压(LCA&amp;树上差分)

题目 思路 首先对于对于高低电压,其实就是二染色问题 有了这个想法之后 自然就会想到图中的环的奇偶性 如何快速的判断呢? 笔者用的是建树+LCA的办法 之后,如果是奇环,环上的所有的边+1 如果是偶环,则-1 用树上差分的办法可以以 \(O(1)\)的优秀时间复杂度处理 之后判断每一个边的值是否为奇环的总数即可 代码 #include<iostream> #include<vector> #include<cstring> #include<cstdio>

poj 3417 Network 【LCA】【树中增新边后 求每条树边被环所覆盖的次数】

Network Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 4251   Accepted: 1223 Description Yixght is a manager of the company called SzqNetwork(SN). Now she's very worried because she has just received a bad news which denotes that DxtNet

poj 3417 Network (LCA,路径上有值)

题意: N个点,构成一棵树.给出这棵树的结构. M条边,(a1,b1)...(am,bm),代表给树的这些点对连上边.这样就形成了有很多环的一个新”树“. 现在要求你在原树中断一条边,在M条边中断一条边,使得新”树“被分成两个部分. 问有多少种方案. 思路: 连上某条新边(a,b),则必定形成一个环.环的路径是a->...->lca(a,b)->...->b,给这些边的值都加1 . 分情况: 在原树中,若一条边的值>=2,去掉这条边,再去掉M条边中的一条,不影响原树的连通性.

bzoj4390: [Usaco2015 dec]Max Flow(LCA+树上差分)

题目大意:给出一棵树,n(n<=5w)个节点,k(k<=10w)次修改,每次给定s和t,把s到t的路径上的点权+1,问k次操作后最大点权. 对于每次修改,给s和t的点权+1,给lca(s,t)和lca(s,t)的父亲的点权-1,每一个点的权就是它与它的子树权和,实际上就是树上的差分,又涨姿势了... 代码如下: uses math; type point=^rec; rec=record data:longint; next:point; end; var n,m,x,y,i,ans,fa,k