天天爱跑步【树上差分】

题目链接


  很好的一道题目,主要是要想到这个方向。

  首先,很容易想到的是,S到T的路径可以拆分成S~LCA和LCA~T这两条,现在,我们假设有一个点x满足条件,那么可以列出怎样的恒等式呢?

  deep[S] - deep[x] = W[x]表示x到S的路径长度为W[x]。这样说明的是到S的,是S~LCA这条链上的,但是换成LCA~T那条链上的话呢,那又是怎样?

W[x] - (deep[S] - deep[LCA]) = deep[x] - deep[LCA],意味着我们走到LCA的剩余时间再走到x,将上面两个式子化简一下,我们可以得到:

deep[S] = deep[x] + W[x](等式一)

2 * deep[LCA] - deep[S] = deep[x] - W[x](等式二)

我们可以发现等式的左边就是一个恒值,不变值。统计答案可以通过统计等式右边的值来得到,于是,我们可以在树上维护左边的值,查询的时候只需要查询该子树下右边的值的个数即可。

  主要的思维就是在这了,其余的部分就不是太难处理了,可以利用差分的方式来解决问题。

#include <iostream>
#include <cstdio>
#include <cmath>
#include <string>
#include <cstring>
#include <algorithm>
#include <limits>
#include <vector>
#include <stack>
#include <queue>
#include <set>
#include <map>
#include <bitset>
#include <unordered_map>
#include <unordered_set>
#define lowbit(x) ( x&(-x) )
#define pi 3.141592653589793
#define e 2.718281828459045
#define INF 0x3f3f3f3f
#define HalF (l + r)>>1
#define lsn rt<<1
#define rsn rt<<1|1
#define Lson lsn, l, mid
#define Rson rsn, mid+1, r
#define QL Lson, ql, qr
#define QR Rson, ql, qr
#define myself rt, l, r
#define MP(a, b) make_pair(a, b)
using namespace std;
typedef unsigned long long ull;
typedef unsigned int uit;
typedef long long ll;
const int maxN = 3e5 + 7;
int N, M, head[maxN], cnt, deep[maxN], root[maxN][20], LOG2[maxN], W[maxN];
struct Eddge
{
    int nex, to;
    Eddge(int a=-1, int b=0):nex(a), to(b) {}
}edge[maxN << 1];
inline void addEddge(int u, int v)
{
    edge[cnt] = Eddge(head[u], v);
    head[u] = cnt++;
}
inline void _add(int u, int v) { addEddge(u, v); addEddge(v, u); }
void pre_dfs(int u, int fa)
{
    root[u][0] = fa; deep[u] = deep[fa] + 1;
    for(int i=0; i<LOG2[N]; i++) root[u][i + 1] = root[root[u][i]][i];
    for(int i=head[u], v; ~i; i=edge[i].nex)
    {
        v = edge[i].to;
        if(v == fa) continue;
        pre_dfs(v, u);
    }
}
inline int LCA(int u, int v)
{
    if(deep[u] < deep[v]) swap(u, v);
    int det = deep[u] - deep[v];
    for(int i=LOG2[det]; i>=0; i--) if((det >> i) & 1) u = root[u][i];
    if(u == v) return u;
    for(int i=LOG2[N]; i>=0; i--)
    {
        if(root[u][i] ^ root[v][i])
        {
            u = root[u][i];
            v = root[v][i];
        }
    }
    return root[u][0];
}
vector<int> delt[maxN], put_in[maxN], redelt[maxN];
int s1[maxN << 1] = {0}, sum[maxN] = {0}, ans[maxN] = {0};
void dfs_1(int u, int fa)
{
    int old = s1[deep[u] + W[u]];
    for(int i=head[u], v; ~i; i=edge[i].nex)
    {
        v = edge[i].to;
        if(v == fa) continue;
        dfs_1(v, u);
    }
    s1[deep[u]] += sum[u];
    ans[u] += s1[deep[u] + W[u]] - old;
    for(auto x : delt[u])
    {
        if(deep[x] - deep[u] == W[u]) ans[u]--; //之后还会被算一遍
        s1[deep[x]] --;
    }
}
unordered_map<int, int> s2;
void dfs_2(int u, int fa)
{
    int old = s2[deep[u] - W[u]];
    for(int i=head[u], v; ~i; i=edge[i].nex)
    {
        v = edge[i].to;
        if(v == fa) continue;
        dfs_2(v, u);
    }
    for(auto x : put_in[u])
    {
        s2[x] ++;
    }
    ans[u] += s2[deep[u] - W[u]] - old;
    for(auto x : redelt[u])
    {
        s2[x] --;
    }
}
inline void init()
{
    cnt = 0;
    for(int i=1; i<=N; i++) head[i] = -1;
    for(int i=1, j = 2, k = 0; i < maxN; i++)
    {
        if(i == j) { k++; j <<= 1; }
        LOG2[i] = k;
    }
}
int main()
{
    scanf("%d%d", &N, &M);
    init();
    for(int i=1, u, v; i<N; i++)
    {
        scanf("%d%d", &u, &v);
        _add(u, v);
    }
    deep[0] = 0;
    pre_dfs(1, 0);
    for(int i=1; i<=N; i++) scanf("%d", &W[i]);
    for(int i=1, Si, Ti, _lca; i<=M; i++)
    {
        scanf("%d%d", &Si, &Ti);
        _lca = LCA(Si, Ti);
        sum[Si]++; delt[_lca].push_back(Si);
        put_in[Ti].push_back(2 * deep[_lca] - deep[Si]);
        redelt[_lca].push_back(2 * deep[_lca] - deep[Si]);
    }
    dfs_1(1, 0);
    dfs_2(1, 0);
    for(int i=1; i<=N; i++) printf("%d%c", ans[i], i == N ? '\n' : ' ');
    return 0;
}
发布了852 篇原创文章 · 获赞 1016 · 访问量 11万+

猜你喜欢

转载自blog.csdn.net/qq_41730082/article/details/104732350