Я решал задачу и понял, что решал не ту задачу, но все же мне интересно правильное ли мое решение?

Задача такая. Дан граф из n вершин и затем дано l[i], r[i]. Для каждого вершины можно выбрать число из отрезка l[i] <= x <= r[i]. Теперь допустим y это максимальная разница между такими числами, что одно число будет числом предка, а второе число будет сына. То есть y = max(allofthe(i, j) where i прямой предок j). Нужно найти минимальное y

Мое решение таково. Давайте бинарить ответ и будем делать для каждого поддерева считать возможный отрезок чисел. И когда мы в какой то вершине допустим ответ для сына это lv[i], rv[i]. То сделаем сканлайн и сперва добавим lv[i] - x(число которое бинарим) и rv[i] + x и потом добавим еще l[i], r[i]. И если будет такая точка что там пересекаются все сыновья + 1, то тогда эта точка может быть нашим ответом. И так строится ответ для текущей вершины.

Вот мой код

#include <iostream>
#include <fstream>
#include <vector>
#include <set>
#include <map>
#include <cstring>
#include <string>
#include <cmath>
#include <cassert>
#include <ctime>
#include <algorithm>
#include <sstream>
#include <list>
#include <queue>
#include <deque>
#include <stack>
#include <cstdlib>
#include <cstdio>
#include <iterator>
#include <functional>
#include <unordered_set>
#include <unordered_map>
#include <stdio.h>
#include <bitset>

using namespace std;

#define ll long long
#define pb push_back
#define mp make_pair
#define f first
#define s second

const ll maxn = 1e6 + 1, maxm = 1e5 + 1;
const ll mod = 998244353, inf = 1e9;

int t, b;
int n;
int p[maxn], s[maxn], q[maxn];
ll lv[maxn], rv[maxn], is = 0;
vector<int> g[maxn];
void dfs(int v, int y){
    if (is)
        return;
    for (auto to : g[v]){
        dfs(to, y);
    }
    vector<pair<ll, int>> sc;
    for (auto to : g[v]){
        sc.pb(mp(lv[to] - y, 0));
        sc.pb(mp(rv[to] + y, 1));
    }
    sc.pb(mp(s[v], 0));
    sc.pb(mp(q[v], 1));
    sort(sc.begin(), sc.end());
    int curr = 0;
    lv[v] = 1e9 + 1;
    rv[v] = -1;
    for (auto it : sc){
        pair<ll, int> cur = it;
        if (cur.s == 0){
            curr += 1;    
            if (curr == (int)g[v].size() + 1){
                lv[v] = min(lv[v], cur.f);
                rv[v] = max(rv[v], cur.f);
            }
        }
        else{
            if (curr == (int)g[v].size() + 1){
                rv[v] = max(rv[v], cur.f);
                lv[v] = min(lv[v], cur.f);
            }
            curr -= 1;
        }
    }
    if (lv[v] > rv[v])
        is = 1;
}
bool check(int x){
    is = 0;
    dfs(1, x);
    return (!is);
}
int main(){
    ios_base::sync_with_stdio(false);
    cin.tie(0), cout.tie(0);
    cin >> t >> b;
    while (t--){
        cin >> n;
        for (int i = 2; i <= n; ++i){
            cin >> p[i];
            g[p[i]].pb(i);
        }
        for (int i = 1; i <= n; ++i){
            cin >> s[i] >> q[i];
        }
        int l = 0, r = 1e9, ans = - 1;
        while (l <= r){
            int mid = (l + r) / 2;
            if (check(mid)){
                 r = mid - 1, ans = mid;
            }
            else{
                 l = mid + 1;
            }
        }
        cout << ans << '\n';
        for (int i = 1; i <= n; ++i){
            g[i].clear();
        }
    }
}

Есть ли решение лучше и мое решение вообще рабочее?

4 лайка

https://ideone.com/g0QnmM

code

Для кода используем обратные тики

\```
\```

Без слэшей, само собой. Или можно просто на кнопку в редакторе нажать
image

3 лайка

Задача : Дано дерево из n вершин корень которого находится в вершине 1, найдите такое число ans что |a_{p_x} - a_x| \leq ans, где a_v это число выбранное для вершины v из отрезка [l_v, r_v].

Пусть S это множество значений a_v при которых будет выполняться условие a_{p_v} - a_v \leq ans для всех вершин в поддереве v, для определённого ans, будем утверждать что данное множество значений будет содержать все целые числа на отрезке [lv_v;rv_v].

Пусть мы хотим получить lv для вершины v и у нас есть все lv для его детей, пусть есть число x такое что lv_v \leq x \leq rv_v, давайте определим что должно выполняться чтобы это было правдой.

Для всех детей u должно выполняться то что существует такое число y что выполняется lv_u \leq y \leq rv_u и |x - y| \leq ans, т.е. то что точка x находится на отрезке [lv_u - ans ;rv_u + ans].Нужно просто в тупую найти пересечение отрезков [lv_u - ans;rv_u + ans] и [l_v; r_v], это и будет lv_v и rv_v, так как в листах lv_v = l_v и rv_v = r_v, то утверждение о множестве значений S выше будет верным.

Можно искать ans с помощью бинарного поиска, так как если существует массива a для ans то он будет существовать и для ans + 1.

Для того чтобы найти пересечение достаточно найти максимум среди всех левых границ и минимум среди всех правых, я не понимаю зачем тут использовать сканлайн. Итоговое решение за O(NlogN), да решение рабочее.

10 лайков

да, чет затупил. Действительно он не нужен

Я вроде ответил на вопрос, если всё понятно то поставь что вопрос решён, если есть вопросы то напиши сюда.

1 лайк

Я вроде бы и до этого нажимал?