天天爱跑步

18年9月24日至18年9月30日

题目1:天天爱跑步

题目简述

见题面

做法简述

树上差分 + lct 乱搞

过关状态 TLE

代码

// luogu-judger-enable-o2
#include<bits/stdc++.h>

using namespace std;
typedef long long LL;
const int N = 6e5 + 7;

int fst[N], nxt[N], D[N << 1], w[N], deep[N], fa[N];
int son[N], top[N], size[N], csum[N], Mark[N];
int siz[N], cnt[N];

struct hh {
    int from, to;
}ma[N];

struct sh {
    int from, to, len, lca;
}mp[N];

vector<int>G[N], V[N];

int n, tot, m;

inline int read() {
    char c = getchar();
    int f = 0;
    while (c < '0' || c > '9') c = getchar();
    while (c >= '0' && c <= '9') f = f * 10 + c - '0', c = getchar();
    return f;
}

void build(int f, int t) {
    ma[++tot] = (hh){f, t};
    nxt[tot] = fst[f], fst[f] = tot;
    return;
}

void dfs1(int x, int f) {
    deep[x] = deep[f] + 1, fa[x] = f, siz[x] = 1;
    for (int i = fst[x]; i; i = nxt[i]) {
        int v = ma[i].to;
        if (v == f) continue;
        csum[v] = csum[x] + 1, dfs1(v, x), siz[x] += siz[v];
        if (!son[x] || siz[son[x]] < siz[v]) son[x] = v;
    }
    return;
}

void dfs2(int x, int st) {
    top[x] = st;
    if (!son[x]) return;
    dfs2(son[x], st);
    for (int i = fst[x]; i; i = nxt[i]) {
        int v = ma[i].to;
        if (v == son[x] || v == fa[x]) continue;
        dfs2(v, v);
    }
    return;
}

int get_lca(int x, int y) {
    int fx = top[x], fy = top[y];
    while (fx != fy) {
        if (deep[fx] < deep[fy]) swap(x, y), swap(fx, fy);
        x = fa[x], fx = top[x];
    }
    return deep[x] > deep[y] ? y : x;
}

void Dfs(int x) {
    int cc = D[deep[x] + w[x]], co = D[w[x] - deep[x] + N];
    for (int i = fst[x]; i; i = nxt[i]) {
        int v = ma[i].to;
        if (v == fa[x]) continue;
        Dfs(v);
    }
    D[deep[x]] += Mark[x];
    for (int i = 0; i < V[x].size(); ++ i) {
        int v = V[x][i];
        D[mp[v].len - deep[mp[v].to] + N]++;
    }
    cnt[x] += D[deep[x] + w[x]] - cc + D[w[x] - deep[x] + N] - co;
    for (int i = 0; i < G[x].size(); ++ i) {
        int v = G[x][i];
        D[deep[mp[v].from]]--, D[mp[v].len - deep[mp[v].to] + N]--;
    }
    return;
}

void solve() {
    int x, y;
    n = read(), m = read();
    for (int i = 1; i < n; ++ i) {
        x = read(), y = read(), build(x, y), build(y, x);
    }
    for (int i = 1; i <= n; ++ i) w[i] = read();
    
    dfs1(1, 0), dfs2(1, 1);
    for (int i = 1; i <= m; ++ i) {
        mp[i].from = read(), mp[i].to = read();
        mp[i].lca = get_lca(mp[i].from, mp[i].to);
        mp[i].len = csum[mp[i].from] + csum[mp[i].to] - 2 * csum[mp[i].lca];
        G[mp[i].lca].push_back(i), V[mp[i].to].push_back(i), Mark[mp[i].from]++;
        if (deep[mp[i].from] == deep[mp[i].lca] + w[mp[i].lca]) cnt[mp[i].lca]--;
    }
    Dfs(1); 
    for (int i = 1; i <= n; ++ i) {
        printf("%d ", cnt[i]);
    }
    return;
}

int main() {
    solve();
    return 0;
}

每周小结

映射时注意数组下标为负数的情况(+一个大数)
拆线路时,如果路线对LCA有贡献,LCA被计算两次,需要减去一次

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值