首页 > 其他分享 >Educational Codeforces Round 138 F Distance to the Path

Educational Codeforces Round 138 F Distance to the Path

时间:2022-10-28 00:33:46浏览次数:75  
标签:hson Distance Educational int Codeforces dfn nex now 节点

Distance to the Path

思维 + 树链剖分

  • 首先与树链剖分无关,先考虑如果只更新一个点的情况

因为更新一个点,它既能向根的方向更新,又能向子树方向更新,非常难维护,于是我们只考虑维护一个节点的子树结点的增值

设数组 \(sum[i][j]\) 为与 \(j\) 结点距离为 \(i\) 的 \(j\) 的子树节点(子树的那一层节点)应当加上多少

  1. 询问:这样询问一个点的值的计算方式就为 \(\sum_{0}^{d}(sum[i][fa_i[j]])\), \(fa_i[j]\) 表示 \(j\) 的第 \(i\) 级祖先,\(0\) 的话就是自己,\(1\) 就是父亲节点

  2. 更新:对于当前点 \(i\) 来说,更新 \(sum[d][i]\) 和 \(sum[d - 1][i]\);然后跳转到父节点,并且 \(d = d - 1\),重复上述过程

对于这个更新,其实要画个图之后理解会更好,就每个结点负责增加两层,一层是因为下一次往父节点走了一步,另一层是因为 \(d - 1\)

如果上面的部分能理解清楚,这题就没啥难度了

注意如果到了根节点的话就不能这样更新了,显然会重复计算,因为没有往父节点走,因此考虑直接给根节点上面加多 \(d\) 层节点就行了(我的代码没加,硬是 if-else 了很多东西,加了会好想很多;前排很多大哥的代码都加了)

  • 然后是维护一个路径的增值,这里考虑用重链剖分

不难想到,对于路径上的非 \(LCA\) 结点 \(i\),只需要维护让 sum[d][i] += k 即可,这个过程就重链剖分板子,把 \(sum\) 改成树状数组就可以了

\(LCA\) 结点直接按上面的方法更新就行

更改的复杂度 \(O(nlog^2n)\)

查询的复杂度 \(O(dlogn)\)

#include <iostream>
#include <cstdio>
#include <vector>
#include <algorithm>
using namespace std;
typedef long long ll;
const int maxn = 2e5 + 10;
inline int lowbit(int x){return x & (-x);}

struct BIT
{
    int n;
    vector<ll>tr;
    BIT(){}
    void init(int _n)
    {
        n = _n;
        tr.resize(n + 1);
    }
    BIT(int _n){init(_n);}
    void add(int x, ll val)
    {
        while(x <= n)
        {
            tr[x] += val;
            x += lowbit(x);
        }
    }
    void add(int l, int r, ll val)
    {
        add(r + 1, -val);
        add(l, val);
    }
    ll query(int x)
    {
        ll ans = 0;
        while(x)
        {
            ans += tr[x];
            x -= lowbit(x);
        }
        return ans;
    }
};

int top[maxn], fa[maxn], dep[maxn], siz[maxn];
int hson[maxn], dfn[maxn], rnk[maxn], tp = 0;
vector<vector<int>>gra;

void dfs1(int now, int pre, int d)
{
    dep[now] = d;
    fa[now] = pre;
    hson[now] = -1;
    for(int nex : gra[now])
    {
        if(nex == fa[now]) continue;
        dfs1(nex, now, d + 1);
        siz[now] += siz[nex];
        if(hson[now] == -1 || siz[nex] > siz[hson[now]]) hson[now] = nex;
    }
}

void dfs2(int now, int t)
{
    dfn[now] = ++tp;
    rnk[tp] = now;
    top[now] = t;
    if(hson[now] != -1)
    {
        dfs2(hson[now], t);
        for(int nex : gra[now])
        {
            if(nex == hson[now] || nex == fa[now]) continue;
            dfs2(nex, nex);
        }
    }
}

int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int n;
    cin >> n;
    gra.resize(n + 1);
    for(int i=1; i<n; i++)
    {
        int a, b;
        cin >> a >> b;
        gra[a].push_back(b);
        gra[b].push_back(a);
    }
    dfs1(1, 0, 1);
    dfs2(1, 1);
    vector<BIT>bit(21, BIT(n));
    int m;
    cin >> m;
    while(m--)
    {
        int op;
        cin >> op;
        if(op == 1)
        {
            int v;
            cin >> v;
            ll ans = 0;
            for(int i=0; i<=20 && v; i++, v=fa[v])
                ans += bit[i].query(dfn[v]);
            cout << ans << "\n";
        }
        else
        {
            int u, v, k, d;
            cin >> u >> v >> k >> d;
            while(top[u] != top[v])
            {
                if(dep[top[u]] < dep[top[v]]) swap(u, v);
                bit[d].add(dfn[top[u]], dfn[u], k);
                u = fa[top[u]];
            }
            if(dep[u] > dep[v]) swap(u, v);
            if(u != v) bit[d].add(dfn[hson[u]], dfn[v], k);
            while(1 != u && d)
            {
                bit[d].add(dfn[u], dfn[u], k);
                bit[d - 1].add(dfn[u], dfn[u], k);
                d--;
                u = fa[u];
            }
            if(d == 0) bit[0].add(dfn[u], dfn[u], k);
            else for(int i=0; i<=d; i++) bit[i].add(1, 1, k);
        }
    }
    cout << endl;
    return 0;
}

标签:hson,Distance,Educational,int,Codeforces,dfn,nex,now,节点
From: https://www.cnblogs.com/dgsvygd/p/16834465.html

相关文章

  • 近期 educational 题目收集
    最近对我比较有启发意义的题。可能很简单但是我都不会/pxARC108E(概率、区间DP)2022.10.16多校联考T4(树的直径、容斥、点分治、NTT)P3239(容斥、概率、DP)2022.10.22联......
  • Codeforces Round #829 (Div. 2)-C1
    C1题目链接:https://codeforces.com/contest/1754/problem/C1emmm,不知道怎么说,做的时候考虑的问题是我通过什么方法来划分整个数组使得题意成立,后面又困在怎么判断是否存......
  • Codeforces Round #707 (Div. 1, based on Moscow Open Olympiad in Informatics) A
    A.GoingHome观察ai<=2.5e6显然我们两数之和最多5e6我们开桶让后怎么暴力让我发愁了显然我们知道我们可能一个数被用了好多次这样显然不行可以想到就是把这个数对......
  • Codeforces Round #643 (Div. 2) C
    C.CountTriangles显然两边之和大于第三边我们可以先预处理出来这个两边之和我们暴力枚举x然后区间赋值[x+b,x+c]+1然后最后暴力枚举第三个边然后将大于第三边的方案......
  • Codeforces Round #673 (Div. 2) C. k-Amazing Numbers
    题面Youaregivenanarrayaconsistingofnintegersnumberedfrom1ton.Let’sdefinethek-amazingnumberofthearrayastheminimumnumberthatoccurs......
  • Codeforces Round #828 (Div. 3) A-F
    比赛链接A题解知识点:贪心,模拟。遇到没用过的数字就给个字母,遇到用过的数字就对照字母是否一致。时间复杂度\(O(n)\)空间复杂度\(O(n)\)代码#include<bits/stdc+......
  • Codeforces Round #632 (Div. 2) / 1333C】- C. Eugene and an array
    题面Eugenelikesworkingwitharrays.Andtodayheneedsyourhelpinsolvingonechallengingtask.Anarrayccisasubarrayofanarraybbifcccanbeobta......
  • Codeforces Round #725 (Div. 3) ABC(双指针)F
    https://codeforces.com/contest/1538AB都没啥好说的,C卡了半天,F挺好写的,找到规律了就直接ac1300的题目卡半天,1500的题目写的顺顺利利,真呆啊我A.StoneGame#include<......
  • Codeforces Round #619 (Motarack's Birthday)
    题面DarkisgoingtoattendMotarack’sbirthday.DarkdecidedthatthegiftheisgoingtogivetoMotarackisanarrayaofnnon-negativeintegers.Darkcr......
  • PAT_甲级_1046 Shortest Distance (20分) (C++)【签到题】
     1,题目描述SampleInput:51241493132541 SampleOutput:3107题目大意有N个出口,从1开始,依次给出出口i+1~i的距离(i从1开始)。最后一个数字为1~N的距离。给出任......