首页 > 其他分享 >Codeforces Round 981 (Div. 3) G

Codeforces Round 981 (Div. 3) G

时间:2024-10-25 20:32:30浏览次数:1  
标签:dep int 981 Codeforces len fa Div d2 d1

G. Sakurako and Chefir

因为没有找到类似的题解,顺便记录下来

题目

给定一棵树,树上有 \(n\) 个顶点,以顶点 \(1\) 为根。樱子带着她的猫 Chefir 穿过这棵树,樱子走神了,Chefir 跑开了。

为了帮助樱子,浩介记录了他的 \(q\) 次猜测。在 \(i\) 次猜测中,他假设Chefir在顶点 \(v_i\) 迷路,并且有 \(k_i\) 次体力。

此外,在每次猜测中,浩介都假设切菲尔可以沿着边移动任意多次:

  • 从顶点 \(a\) 到顶点 \(b\) ,如果 \(a\) 是 \(b\) 的祖先,体力不会发生变化;
  • 从顶点 \(a\) 到顶点 \(b\) ,如果 \(a\) 不是 \(b\) 的祖先,那么切菲尔的体力会减少 \(1\)。

如果切菲尔的体力为 \(0\) ,则无法使用第二种类型的移动。

对于每个假设,你的任务是找出切菲尔在拥有 \(k_i\) 体力的情况下,从顶点 \(v_i\) 到达最远顶点的距离。

分析

在一颗树中,某个点最远的一个点一定可以作为直径的一个端点(参考2次bfs/dfs求直径)

对于每次查询,\(Chefir\) 可以到达的范围就是以 \(v\) 的第 \(k\) 个祖先为根的子树

所以求出每棵子树中的直径端点,每次的最远点就是这两个点之一

在树dp求直径的时候顺便求出端点

细节在代码中有注释

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int>PII;
const int N=1e6+10;
const int mod=998244353;
const int INF  = 0x3f3f3f3f;
const ll INFll  = 0x3f3f3f3f3f3f3f3f;
#define endl "\n" 

vector<vector<int>>adj(N);
struct gflca{ // 简单的lca
    int n, m, root;
    vector<vector<int>> fa;
    vector<int> dep;
    void init(int _n, int _m, int _root) {
        n = _n + 10;
        m = _m;
        root = _root;
        fa.resize(n);
        dep.resize(n);

        for(int i = 0; i < n; i ++) {
            fa[i].resize(m);
            dep[i] = 0;
            for(int j = 0; j < m; j ++) fa[i][j] = 0;
        }

        dfs(root, 0);
    }

    void dfs(int u, int father) {
        dep[u] = dep[father] + 1;
        fa[u][0] = father;
        for(int i = 1; (1 << i) <= dep[u]; i ++) {
            fa[u][i] = fa[fa[u][i - 1]][i - 1];
        }

        for(auto v: adj[u]) {
            if(v != father) dfs(v, u);
        }
    }

    int LCA(int x, int y) {
        if(dep[x] < dep[y]) swap(x, y);
        for(int i = m - 1; i >= 0; i --) {
            if(dep[x] - (1 << i) >= dep[y]) x = fa[x][i]; 
        }
        if(x == y) return x;
        for(int i = m - 1; i >= 0; i --) {
            if(fa[x][i] != fa[y][i]) {
                x = fa[x][i];
                y = fa[y][i];
            }
        }
        return fa[x][0];
    }

    int len(int x, int y) {
        return dep[x] + dep[y] - 2*dep[LCA(x, y)];
    }

    int find(int u, int k) { // 查找u的第k个祖先,注意特判0
        for(int i = m - 1; i >= 0; i --) {
            if(((k >> i) & 1)) {
                u = fa[u][i];
            }
        }
        if(u == 0) u = root;
        return u;
    }

}lca;

PII d1[N],d2[N], d[N]; //d1[u]存的是以u一个端点,另一个点是u子树中的叶子所组成的最长的一条链,这里存了长度和这个叶子编号
                        // d2和d1差不多,只不过是第二长的 
                        // d 就u为根的子树直径的两个端点
int len[N];             // len 为直径长度

void dfs(int u, int fa) { 
    d1[u] = d2[u] = {0, u};
    for(auto v : adj[u]) {
        if(fa == v) continue;
        dfs(v, u);
        // 很经典的树dp求直径的方法,只不过多求了个端点 注意最长链和次长链不能来源同一个儿子 
        if(d1[v].first + 1 >= d1[u].first) {
            d2[u] = d1[u];
            d1[u] = d1[v];
            d1[u].first += 1;
        } else if(d1[v].first + 1 >= d2[u].first) {
            d2[u] = d1[v];
            d2[u].first += 1;
        }
    }

    len[u] = d1[u].first + d2[u].first; 
    d[u] = {d1[u].second, d2[u].second}; // 直径过u

    for(auto v : adj[u]) { // 直径在某个子树内
        if(v == fa) continue;
        if(len[v] > len[u]) {
            len[u] = len[v];
            d[u] = d[v];
        }
    }
}


void solve()
{
    int n; cin >> n;
    for(int i = 1; i < n; i ++) {
        int u, v; cin >> u >> v;
        adj[u].push_back(v);
        adj[v].push_back(u);
    }
    lca.init(n,25,1);
    dfs(1, -1);

    int q; cin >> q;
    while(q --) {
        int u, k; cin >> u >> k;
        int fa = lca.find(u, k);
        cout << max(lca.len(u, d[fa].first), lca.len(u,d[fa].second)) << " ";
    }
    cout << endl;


    for(int i = 1; i <= n; i ++) {
        len[i] = 0;
        d[i] = d1[i] = d2[i] = {0, 0};
        adj[i].clear();
    }
}


signed main()
{
    ios::sync_with_stdio(false);
    cin.tie(0),cout.tie(0);
    cout << setprecision(11) << fixed;
    int t;t=1;
    cin>>t;
    for(int i=1;i<=t;i++){
        //printf("Case %d: ",i);
        solve();
    }
}

标签:dep,int,981,Codeforces,len,fa,Div,d2,d1
From: https://www.cnblogs.com/Haborym/p/18503209

相关文章

  • 倒计时功能实现:认识了css选择器 div[id^=“countdown-“]
    html倒计时<!DOCTYPEhtml><htmllang="zh-CN"><head><metacharset="UTF-8"><metaname="viewport"content="width=device-width,initial-scale=1.0"><title>倒计时功能实现</ti......
  • 【CodeForces训练记录VP】Codeforces Round 933 (Div. 3)
    https://codeforces.com/contest/1941训练情况50min后罚坐反思C题刚开始思路错了,以为是删字符串最后面,然后漏考虑掉两字符串部分拼接的情况A题直接模拟,求\(a_i+b_j\lek\)的对数。#include<bits/stdc++.h>#defineintlonglongusingnamespacestd;voidsolve......
  • CF 981 Review
    CF981Review打的最差的一场Div.3虽然可能有Div.3是ICPC赛制的原因,但是本质上还是自己太菜了。A模拟Code#include<bits/stdc++.h>usingnamespacestd;template<typenameT>inlinevoidre(T&x){ x=0;intf=1;charc=getchar(); while(!isdigit(c)){if(c=='-')f=-1;......
  • Codeforces Round 972 (Div. 2)
    CodeforcesRound972(Div.2)总结A#include<bits/stdc++.h>usingnamespacestd;intn;chara[]={'a','e','i','o','u'};voidsolve(){cin>>n;intx=n/5,y=n%5;for(inti=0;i<5;......
  • CodeForces - 788C - 完全背包
    题目表示(x1*a[1]+x2*a[2]+...+xk*a[k])/((x1+x2+...+xk)*1000)=n/1000,可以推出(x1*a[1]+x2*a[2]+...+xk*a[k])=n*(x1+x2+...+xk),进而得出(x1*(a[1]-n)+x2*(a[2]-n)+...+xk*(a[k]-n))=0,这样处理之后就和我之前......
  • Codeforces Round 980 (Div. 2)
    CodeforcesRound980(Div.2)总结A简单小学算数题。如果\(b\lea\),直接输出\(a\)。否则,列方程\(a-x=b-2x\),\(x=b-a\),输出\(a-x\),即\(2a-b\)。#include<iostream>#include<cstdio>#include<cstring>#include<algorithm>#include<c......
  • [算法题解] Codeforces round 979 --D. QED's Favorite Permutation
    题目链接:https://codeforces.com/contest/2030/problem/D题目:题解:FavotitePermutation即每个数满足i=p[i];此题中,p数组每次询问后保持不变,s根据询问而改变。因此每次需要进行交换的数的位置是相同的,只需要检验s变更后,操作能否满足交换需求与否。故创建需数组need,预处理nee......
  • Codeforces Round 966 (Div. 3) A - G
    linkvp赛时过了ABD,CE没做出来,唐完了eee感觉自己真的可以退役了A-PrimaryTaskB-SeatinginaBusC-NumericStringTemplate这题很简单,开两个map扫一遍就可以了,但是赛时我只开了一个,然后居然没调出来qwq,降智D-RightLeftWrong很显然的贪心,最左边配对......
  • HTML布局常用标签——div和span
    HTML布局常用标签——div和span在HTML的世界里,div和span是两位不可或缺的老朋友,它们虽然看似简单,却在网页布局和样式设计中发挥着举足轻重的作用。今天,我们就来聊聊这两位“无意义”却极其实用的标签——div和span。一、div:块级元素的大块头1.定义与特点div,全称“division”,......
  • EPIC Institute of Technology Round Summer 2024 (Div. 1 + Div. 2) E. Wonderful Tr
    题目链接EPICInstituteofTechnologyRoundSummer2024(Div.1+Div.2)E.WonderfulTree!思路题目要求令所有的av≤......