模板【树上点差分】

PART1(算法思想简介)

1.实现

2.时间复杂度

3.特别优势

4.适用情况

5.需要注意的点

6.函数、变量名的解释+英文

7.dalao分析

PART2(算法各种类型(并附上代码))

 1.代码

#include<cstdio>
#include<cmath>
#include<algorithm>
#include<set>
#include<map>
#include<cstring>
#include<string>
#include<vector>
#include<queue>
#include<iomanip>
#include<iostream>#include<stack>
using namespace std;
#define inf 0x3f3f3f3f
const int MAXN = 5e4+10;
const int MAXM = 1e5+10;
//快读
inline int read();
//与边相关
struct edge
{
    int u, v, next, w;
} e[MAXM];
int p[MAXN], eid;
inline void InitEdge();
inline void Insert(int u, int v, int w = 0);
//lca:先调用LcaPre一次,然后自由调用Lca
int dep[MAXN];//深度
int parent[MAXN][20];
void LcaInit();
void LcaDfs(int u);
void LcaPre(int n, int root);//n:结点个数,root:根节点
int Lca(int x, int y);//x,y:任意两个结点,返回他们的公共祖先结点
//树上差分
int sum[MAXN];
void TreeNodeDifference(int u, int v, int change);
//求最终结果
int ans;

void Gmax(int u, int fa);
//main
int main()
{
    //freopen("in.txt","r", stdin);
    //freopen("out.txt","w", stdout);
    ios::sync_with_stdio(false);
    InitEdge();
    int n, k;
    cin >> n >> k;
    int u,v;
    for(int i=1; i<n; i++)
    {
        cin>>u>>v;
        Insert(v, u);
        Insert(u, v);
    }
    LcaPre(n, 1);
    while(k--)
    {
        cin >> u >>v;
        TreeNodeDifference(u, v, 1);
    }
    Gmax(1, -1);
    cout << ans;
    return 0;
}
//函数定义
//快读
inline int read()//快读板子
{
    int x=0;
    char c=getchar();
    while(c<'0'||c>'9')
        c=getchar();
    while(c>='0'&&c<='9')
    {
        x=(x<<1)+(x<<3)+c-'0';
        c=getchar();
    }
    return x;
}
inline void InitEdge()
{
    memset(p, -1, sizeof(p));
    eid = 0;
}
inline void Insert(int u, int v, int w)
{
    e[eid].next = p[u];
    e[eid].u = u;
    e[eid].v = v;
    e[eid].w = w;
    p[u] = eid++;
}
//lca
void LcaDfs(int u)
{
    for(int i = p[u]; i != -1; i = e[i].next)
    {
        if(dep[e[i].v] == -1)
        {
            dep[e[i].v] = dep[u]+1;
            parent[e[i].v][0] = u;
            LcaDfs(e[i].v);
        }
    }
}
void LcaPre(int n, int root)
{
    LcaInit();
    dep[root] = 0;
    LcaDfs(root);
    for(int level = 1; (1 << level) <= n; level++)
        for(int i = 1; i <= n; i++)
        {
            parent[i][level] = parent[parent[i][level-1]][level-1];
        }
}
void LcaInit()
{
    memset(dep, -1, sizeof(dep));
}
int Lca(int x, int y)
{
    int i, j;//之后求出来的i要使用两次,所以用的时候用j代替i
    if(dep[x] < dep[y])//x是更深的那个
    {
        swap(x, y);
    }
    //找到深度不大于dep[x]的最深的2^i
    for(i = 0; (1<<i) <= dep[x]; i++);
    i--;
    //倍增使得dep[x]==dep[y]
    for(j = i; j >= 0; j--)
    {
        if(dep[x] - (1 << j) >= dep[y])
        {
            x = parent[x][j];
        }
    }
    //直接y就是x的最近公共祖先
    if(x == y)
    {
        return x;
    }
    //找到公共祖先
    for(j = i; j >= 0; j--)
    {
        if(parent[x][j] != parent[y][j]) //就是要不相等时才跳,相等时跳那就跳多了而且不行不行
        {
            x = parent[x][j];
            y = parent[y][j];
        }
    }
    return parent[x][0];//因为上面看到相等就不求得跳,所以最终答案是这个!!!
}
//树上差分
void TreeNodeDifference(int u, int v, int change)
{
    int fa = Lca(u, v);
    sum[u]+=change, sum[v]+=change;
    sum[fa]-=change, sum[parent[fa][0]]-=change;
}
//Gmax
void Gmax(int u, int fa)
{
    for(int i = p[u]; ~i; i = e[i].next)
    {
        int v = e[i].v;
        if(v == fa)
            continue;
        Gmax(v, u);
        sum[u] += sum[v];
    }
    ans = max(ans, sum[u]);
}
View Code

 

PART3(算法的延伸应用)

 

PART4(对算法深度的理解)

 

PART5(与其相关的有趣题目)

 

posted @ 2021-07-15 10:56  bear_xin  阅读(41)  评论(0)    收藏  举报