[LCA 树上差分边差分] 闇の連鎖

Posted 鱼竿钓鱼干

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[LCA 树上差分边差分] 闇の連鎖相关的知识,希望对你有一定的参考价值。

[LCA 树上差分边差分] 闇の連鎖

题目

题目链接

思路

主要参考蓝书
这题实际上是统计边被覆盖的次数
附加边(x,y)的效果就是把树上路径(x,y)的边全部+1
我们可以使用树上差分做标记来优化

void Edge_Mark(int x,int y,int v){//边差分标记
    int lca=LCA(x,y);
    mark[x]+=v;mark[y]+=v;mark[lca]-=2*v;
}

回溯统计子树和可以知道每条边的被覆盖次数
求解答案贡献的时候分类讨论
主要边被覆盖0次,附加边随便选
主要边被覆盖1次,附加边唯一确定
主要边被覆盖2次,无可行方案

代码

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10,M=25;
int n,m,ans;
vector<int>root[N];
int fa[N][M],mark[N],LG[N],dep[N];
void prework(){
    LG[1]=0;
    for(int i=2;i<=N;i++)LG[i]=LG[i/2]+1;
}
void dfs(int u,int v){
    dep[u]=dep[v]+1;
    fa[u][0]=v;
    for(auto to:root[u])
        if(to!=v)dfs(to,u);
}
int LCA(int x,int y){
	if(dep[x]<dep[y])swap(x,y);
	while(dep[x]>dep[y])
		x=fa[x][LG[dep[x]-dep[y]]];
	if(x==y)return y;
	for(int i=20;i>=0;i--)
		if(fa[x][i]!=fa[y][i])
			x=fa[x][i],y=fa[y][i];
	return fa[x][0];
}

void Edge_Mark(int x,int y,int v){//边差分标记
    int lca=LCA(x,y);
    mark[x]+=v;mark[y]+=v;mark[lca]-=2*v;
}

int get_ans(int u,int v){
    int res=mark[u];
    for(auto to:root[u]){
        if(to!=v){
            int s=get_ans(to,u);//获取子树边中被附加边覆盖的次数
            if(s==0)ans+=m;//如果被覆盖数为0,那么任意附加边都可以切
            else if(s==1)ans++;//如果被覆盖数为1,那么被切掉的附加边是唯一确定的
            //其他情况没法实现
            res+=s;
        }   
    }
    return res;
}
int main(){
    cin>>n>>m;
    for(int i=1;i<n;i++){
        int x,y;cin>>x>>y;
        root[x].push_back(y);
        root[y].push_back(x);
    }
    dfs(1,0);
    for(int j=1;j<=20;j++)
        for(int i=1;i<=n;i++)
            fa[i][j]=fa[fa[i][j-1]][j-1];
    for(int i=1;i<=m;i++){
        int x,y;cin>>x>>y;
        Edge_Mark(x,y,1);
    }
    get_ans(1,0);
    cout<<ans;
    return 0;
}

以上是关于[LCA 树上差分边差分] 闇の連鎖的主要内容,如果未能解决你的问题,请参考以下文章

树上差分:闇の連鎖 题解

poj3417 闇の連鎖 树上差分By cellur925

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

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

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

[LCA 树上差分 点差分 板子] Max Flow P