首页 > 其他分享 >牛客周赛 Round 67 F

牛客周赛 Round 67 F

时间:2024-11-11 21:07:54浏览次数:1  
标签:int mid Round 牛客 depth 67 pair using 节点

F.小Z的树迁移

思路

赛事没想出来如何做,可以发现,对于一个节点u,走d步所走的最远距离即为 深度为depthu+d且位于u的子树之中的节点距离根节点距离的最大值 再减去节点u距离根节点的距离即为结果

当我们查询时该如何做?

第一步,我们先给每个节点按照dfs序进行编号,这样保证了同一子树的节点的编号在\(l-r\)的一个连续区间内

第二步,把每个节点存进对应的深度容器中,当我们处理一个查询时,查询的深度即为depth[u]+d,我们找到对应深度容器,由于容器中满足条件的点为一段连续的区间,我们可以通过二分查询这段区间的首尾

第三步,预处理st表维护区间最大值

注意:处理二分边界条件

牛客官方题解

代码

#include <bits/stdc++.h>
using namespace std;
#define endl '\n'
using ll = long long;
using ull = unsigned long long;
using pii = pair<int, int>;
using piii = pair<int, pii>;
using pll = pair<ll, ll>;
using plll = pair<ll, pll>;
using plii = pair<ll, pii>;
#define fi first
#define se second
const int INF = 0x3f3f3f3f;
const ull mod1 = (1ull << 61) - 1, mod2 = 1e9 + 7;
const ull base1 = 131, base2 = 13331;
// mt19937 rnd(time(0));

const int mod = 998244353;

void solve() {
    int n;
    cin >> n;
    vector<vector<pii>> g(n + 1);
    for (int i = 1; i < n; i++) {
        int a, b, w;
        cin >> a >> b >> w;
        g[a].push_back({b, w}), g[b].push_back({a, w});
    }
    vector<int> depth(n + 1), siz(n + 1);
    vector<vector<pair<int, ll>>> tups(n + 1);
    vector<ll> dist(n + 1), dfn(n + 1);
    int cnt = 0;
    auto dfs = [&](auto&& self, int u, int fa) -> void {
        dfn[u] = ++cnt;
        depth[u] = depth[fa] + 1;
        siz[u] = 1;
        for (auto [y, w] : g[u]) {
            if (y == fa)
                continue;
            dist[y] = dist[u] + w;
            self(self, y, u);
            siz[u] += siz[y];
        }
    };
    dfs(dfs, 1, 0);
    for (int i = 1; i <= n; i++) {
        tups[depth[i]].push_back({dfn[i], dist[i]});
    }
    for (int i = 1; i <= n; i++) {
        auto& v = tups[i];
        sort(v.begin(), v.end());
    }
    vector<vector<vector<ll>>> sts(n + 1);
    for (int i = 1; i <= n; i++) {
        int len = tups[i].size();
        auto& v = sts[i];
        auto& data = tups[i];
        if (len) {
            int flen = log2(len) + 1;
            v.resize(len);
            for (int j = 0; j < len; j++)
                v[j].resize(flen);
            for (int j = 0; j < flen; j++) {
                for (int k = 0; k + (1 << j) - 1 < len; k++) {
                    if (j == 0)
                        v[k][j] = data[k].se;
                    else {
                        v[k][j] = max(v[k][j - 1], v[k + (1 << j - 1)][j - 1]);
                    }
                }
            }
        }
    }
    auto get = [&](int l, int r, int dep) {
        auto& v = sts[dep];
        int k = log2(r - l + 1);
        // cout<<l<<" "<<r<<" "<<v.size()<<" "<<dep<<" "<<k<<endl;
        // cout<<v[0].size()<<endl;
        return max(v[l][k], v[r - (1 << k) + 1][k]);
    };
    int q;
    cin >> q;
    while (q--) {
        int u, d;
        cin >> u >> d;
        int dep = depth[u] + d;
        if (dep > n) {
            cout << -1 << endl;
            continue;
        }
        int bg = dfn[u], ed = dfn[u] + siz[u] - 1;
        auto& v = tups[dep];
        if (v.size() == 0) {
            cout << -1 << endl;
            continue;
        }
        int l1 = 0, r1 = v.size() - 1;
        while (l1 < r1) {
            int mid = l1 + r1 >> 1;
            if (v[mid].fi >= bg)
                r1 = mid;
            else
                l1 = mid + 1;
        }
        int l2 = 0, r2 = v.size() - 1;
        while (l2 < r2) {
            int mid = l2 + r2 + 1 >> 1;
            if (v[mid].fi <= ed)
                l2 = mid;
            else
                r2 = mid - 1;
        }
        if (l2 < l1) {
            cout << -1 << endl;
            continue;
        }
        auto tt = v.front().fi;
        if (v.size() == 1 && (tt < bg || tt > ed)) {
            cout << -1 << endl;
            continue;
        }
        cout << get(l1, l2, dep) - dist[u] << endl;
    }
}

int main() {
    cin.tie(nullptr);
    ios::sync_with_stdio(false);
    int _ = 1;
    // cin >> _;
    while (_--) {
        solve();
    }
    return 0;
}

标签:int,mid,Round,牛客,depth,67,pair,using,节点
From: https://www.cnblogs.com/mgnisme/p/18540580

相关文章

  • D题 :K (牛客周赛 Round 67)
    题目链接:题目链接:K题目:分析: 做题一定要认真读题,认真再认真。根据题意可知:极大不同区间的数量是k,但是长度并不一定是k。我看了示例1后,正好3个区间,区间长度都是3,于是认为极大不同区间的长度也是k了。但是题目中没有明确要求,所以极大区间长度不一定为k,只是数量恰好为k。话......
  • Educational Codeforces Round 158 (Rated for Div. 2) - VP记录
    A.LineTrip油量必须支持车子通过所有加油站间的空间,还要注意开回来的时候终点不能加油。点击查看代码#include<cstdio>#include<algorithm>usingnamespacestd;constintN=55;intn,x,a[N];intmain(){ intT;scanf("%d",&T); while(T--) { scanf("%d%d",&am......
  • 题解:P10967 [IOI2000] 邮局(原始版)
    思路首先将坐标排序。定义\(dp_{i,j}\)为前\(i\)个村庄放\(j\)个邮局的前\(i\)个村庄的最小距离总和,\(f(i,j)\)表示村庄区间\([i,j]\)内放一个村庄时该区间的总和。转化式易得\(dp_{i}{j}=dp_{k}{j-1}+f(k+1,i),k\in[0,i)\)。则本题的难点就为求\(f(k-1,i)\)。......
  • CF Round 985
    比赛链接A.Set#include<iostream>#include<cstdio>usingnamespacestd;intmain(){intt;scanf("%d",&t);while(t--){intl,r,k;scanf("%d%d%d",&l,&r,&k);printf("%......
  • Codeforces Round 985 简略复盘
    A.Set题目描述给你一个正整数\(k\)和由\(l\)至\(r\)(含)的所有整数组成的集合\(S\)。您可以执行以下两步运算的任意次数(可能为零):首先,从集合\(S\)中选择一个数字\(x\),使得\(S\)(包括\(x\)本身)中至少有\(k\)个\(x\)的倍数;然后,从\(S\)中删除\(x\)(注意没......
  • 代码随想录算法训练营day43| 300.最长递增子序列 674. 最长连续递增序列 718. 最长
    学习资料:https://programmercarl.com/0300.最长上升子序列.html#算法公开课动态规划系列之子序列学习记录300.最长递增子序列(长度最少为1;dp[i]代表到i为止的最长子序列的长度;i的值根据i之前比如j的值来判断;每个地方都有可能获得最长长度)点击查看代码classSolution:def......
  • Educational Codeforces Round 144 (Rated for Div. 2) C. Maximum Set
    我们要选出最长的子序列,使得每一个数都是前一个数的倍数。因此自然我们可以想到选择最小值然后每次乘\(2\)。所以有\(l\times2^k\ler\),即\(k=\left\lfloor\log_2\frac{r}{l}\right\rfloor\)。所以最大的集合大小就是\(k+1\)。然后考虑最大的集合中最小值可能不同,我假设......
  • 牛客周赛67
    c因为c的数据比较小,所以只需要通过便利c,然后计算出加号左右两边的数字,因为题目给的n的意思其实是加号左右两边的数字位数确定了,所以只要保证得出的两边的数字位数满足条件就好(写的时候吧c的数据大小看成10的n次方了。。。硬是用数学公式算了一小时)点击查看代码/*台州第一深......
  • Codeforces Round 983 (Div. 2) - A
    题目链接:https://codeforces.com/problemset/problem/2032/A题解代码:#include<bits/stdc++.h>usingnamespacestd;voidsolve(){intn;cin>>n;intcount0=0,count1=0;for(inti=0;i<n*2;i++){intx;......
  • Sigrity SPEED2000 Power Ground Noise Simulation模式如何进行信号时域仿真操作指导(
    SigritySPEED2000PowerGroundNoiseSimulation模式如何进行信号时域仿真操作指导(一)-单个IBIS模型SigritySPEED2000PowerGroundNoiseSimulation模式如何进行信号时域仿真操作指导(一)-单个信号是用晶体管模型来作为驱动,下面以单个IBIS模型作为驱动来说明如何进行时......