AcWing352 闇の連鎖(树上差分+lca)

这道题的我们知道如果在两个点之间有附加边,其实就相当于在这个回路上的每条边都权值+1,这样就可以通过差分数组来快速求取大小

这里的精髓就是在输入的两个位置+1,而在他们的lca上-=2;

#include<iostream>
#include<queue>
#include<map>
#include<vector>
#include<cstdio>
#include<algorithm>
#include<stack>
#include<cstring>
using namespace std;
typedef long long ll;
const int N=1e6+10;
const int inf=0x3f3f3f3f;
int e[N],ne[N],h[N],idx;
int fa[N][16];
int depth[N];
int d[N];
int m;
void add(int a,int b){
    e[idx]=b,ne[idx]=h[a],h[a]=idx++;
}
void bfs(){
    memset(depth,0x3f,sizeof depth);
    depth[0]=0,depth[1]=1;
    queue<int> q;
    q.push(1);
    while(q.size()){
        int t=q.front();
        q.pop();
        int i;
        for(i=h[t];i!=-1;i=ne[i]){
            int j=e[i];
            if(depth[j]>depth[t]+1){
                depth[j]=depth[t]+1;
                q.push(j);
                fa[j][0]=t;
                for(int k=1;k<=15;k++){
                    fa[j][k]=fa[fa[j][k-1]][k-1];
                }
            }
        }
    }
}
int lca(int a,int b){
    if(depth[a]<depth[b])
        swap(a,b);
    int i;
    for(i=15;i>=0;i--){
        if(depth[fa[a][i]]>depth[b])
            a=fa[a][i];
    }
    if(a==b)
        return a;
    for(i=15;i>=0;i--){
        if(fa[a][i]!=fa[b][i]){
            a=fa[a][i];
            b=fa[b][i];
        }
    }
    return fa[a][0];
}
int ans=0;
int dfs(int u,int p){
    int res=d[u];
    int i;
    for(i=h[u];i!=-1;i=ne[i]){
        int s=0;
        int j=e[i];
        if(j==p)
            continue;
        s+=dfs(j,u);
        if(s==0)
            ans+=m;
        else if(s==1)
            ans++;
        res+=s;
    }
    return res;
}
int main(){
    int n;
    cin>>n>>m;
    int i;
    memset(h,-1,sizeof h);
    for(i=1;i<n;i++){
        int a,b;
        scanf("%d%d",&a,&b);
        add(a,b);
        add(b,a);
    }
    bfs();
    for(i=1;i<=m;i++){
        int a,b;
        scanf("%d%d",&a,&b);
        int p=lca(a,b);
        d[a]++,d[b]++,d[p]-=2;
    }
    dfs(1,-1);
    printf("%d\n",ans);
}

原文地址:https://www.cnblogs.com/ctyakwf/p/12499702.html

时间: 2024-10-08 12:26:14

AcWing352 闇の連鎖(树上差分+lca)的相关文章

poj3417 闇の連鎖 【树上差分】By cellur925

闇の連鎖(yam.pas/c/cpp)题目描述传说中的暗之连锁被人们称为 Dark.Dark 是人类内心的黑暗的产物,古今中外的勇者们都试图打倒它.经过研究,你发现 Dark 呈现无向图的结构,图中有 N 个节点和两类边,一类边被称为主要边,而另一类被称为附加边.Dark 有 N – 1条主要边,并且 Dark 的任意两个节点之间都存在一条只由主要边构成的路径.另外,Dark 还有 M 条附加边.你的任务是把 Dark 斩为不连通的两部分.一开始 Dark的附加边都处于无敌状态,你只能选择一条主

树上差分:闇の連鎖 题解

题目描述 传说中的暗之连锁被人们称为 Dark. Dark 是人类内心的黑暗的产物,古今中外的勇者们都试图打倒它. 经过研究,你发现 Dark 呈现无向图的结构,图中有 N 个节点和两类边,一类边被称为主要边,而另一类被称为附加边. Dark 有 N – 1 条主要边,并且 Dark 的任意两个节点之间都存在一条只由主要边构成的路径. 另外,Dark 还有 M 条附加边. 你的任务是把 Dark 斩为不连通的两部分. 一开始 Dark 的附加边都处于无敌状态,你只能选择一条主要边切断. 一旦你切

【COGS 2434】 暗之链锁 树上差分+LCA

差分就是把一个值拆成许多差的和如 1 2 4 6 9 那么 把这个东西拆成 1 1 2 2 3 就是了,当然也可以理解为对一个问题分解为多个子问题并对其进行操作来得到原问题的答案. 树上差分就更玄妙了,它既可以把原问题拆成他到根节点的所有点,也可以拆成子树,拆成子树的话修改一个点影响的是他到根的路径上所有点,根据这个我们可以再加上LCA来解决许多问题. 这道题:I. 我们可以看出我们可以把它转化成一棵有根树,那么两部分一定是一个子树和其他 II. 那些虚边,都是砍断实边之后的藕断丝连,至于如何计

poj3417 Network 树上差分+LCA

题目传送门 题目大意:给出一棵树,再给出m条非树边,先割掉一条树边,再割掉一条非树边,问有几种割法,使图变成两部分. 思路:每一条 非树边会和一部分的树边形成一个环,分三种情况: 对于那些没有形成环的树边来说,割掉这条边,就已经使图分离,然后随便割一条非树边就可以了,所以这样的边每次答案加上m. 对于那些只存在在一个环中的树边来说,割掉这条边,再割一条和他存在于同一个环中的那条非树边,也能合法,所以加一. 对于存在于多个环中的树边,无论怎样,都无法合法. 也就是此时我们将题目转化成了树上的覆盖问

[树上差分][lca] Luogu P3258 松鼠的新家

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

luogu P1600 天天爱跑步 |树上差分+LCA

题目描述 小c 同学认为跑步非常有趣,于是决定制作一款叫做<天天爱跑步>的游戏.<天天爱跑步>是一个养成类游戏,需要玩家每天按时上线,完成打卡任务. 这个游戏的地图可以看作一一棵包含 nnn 个结点和 n?1n-1n?1 条边的树,每条边连接两个结点,且任意两个结点存在一条路径互相可达.树上结点编号为从 111 到 nnn 的连续正整数. 现在有 mmm 个玩家,第 iii 个玩家的起点为 sis_isi?,终点为 tit_iti?.每天打卡任务开始时,所有玩家在第 000 秒同时

[填坑]树上差分 例题:[JLOI2014]松鼠的新家(LCA)

今天算是把LCA这个坑填上了一点点,又复习(其实是预习)了一下树上差分.其实普通的差分我还是会的,树上的嘛,也是懂原理的就是没怎么打过. 我们先来把树上差分能做到的看一下: 1.找所有路径公共覆盖的边 例题:[NOIP2015]运输计划 (然而我还没过就先不讲了) 反正就是中间有一步要求一条边被所有计划公共覆盖. 那么怎么求它呢?暴力(滚粗).我们有一个非常好的方法就是树上差分(记录tmp为差分数组) 询问操作为从叶子节点的权值向上累加到root 在一条路径u→ v,如果tmp[u]++,那么我

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

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

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

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