CodeForces - 293E Close Vertices

题意:

给定一棵有 n n 个结点的树,边带权,求有多少对结点 ( i < j ) (i \lt j) 满足 i i j j 的路径长度不大于 l l 且 路径上的边权和不大于 w w ( n 1 0 5 ) (n\leq 10^5)

链接:

https://vjudge.net/problem/CodeForces-293E

解题思路:

点分治, c a l cal 子问题即求类似二维偏序的问题,先一维排序,用双指针,另一维用树状数组统计答案。

参考代码:

#include<bits/stdc++.h>

using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
#define sz(a) ((int)a.size())
#define pb push_back
#define lson (rt << 1)
#define rson (rt << 1 | 1)
#define gmid (l + r >> 1)
const int maxn = 1e5 + 5;
const int inf = 0x3f3f3f3f;
const int mod = 1e9 + 7;

vector<pii> G[maxn];
pii dis[maxn];
int siz[maxn], vis[maxn], rub[maxn];
int n, L, W, tn, rmn, rt, tot, top;
ll ans;

struct BIT{

    int c[maxn];
    #define lowb(x) ((x)&(-x))
    void update(int x, int val){

        ++x;
        while(x <= n) c[x] += val, x += lowb(x);
    }
    int query(int x){

        int ret = 0; ++x; x = min(x, n);
        while(x > 0) ret += c[x], x -= lowb(x);
        return ret;
    }
} c;

void getRt(int u, int f){

    int mx = 0; siz[u] = 1;
    for(auto &e : G[u]){

        int v = e.second, w = e.first;
        if(v == f || vis[v]) continue;
        getRt(v, u);
        siz[u] += siz[v];
        mx = max(mx, siz[v]);
    }
    mx = max(mx, tn - siz[u]);
    if(mx < rmn) rmn = mx, rt = u;
}

void dfs(int u, int f, int cnt, int d){

    dis[++tot] = {d, cnt};
    for(auto &e : G[u]){

        int v = e.second, w = e.first;
        if(v == f || vis[v]) continue;
        dfs(v, u, cnt + 1, d + w);
    }
}

void cal(int u, int cnt, int d, int flg){

    tot = 0;
    dfs(u, 0, cnt, d);
    sort(dis + 1, dis + 1 + tot);
    for(int l = 1, r = tot; r >= 1; --r){

        while(l <= tot && dis[r].first + dis[l].first <= W){

            c.update(dis[l].second, 1);
            rub[++top] = dis[l].second;
            ++l;
        }
        ans += flg * c.query(L - dis[r].second);
    }
    while(top) c.update(rub[top--], -1);
}

void dfz(int u){

    vis[u] = 1;
    cal(u, 0, 0, 1);
    for(auto &e : G[u]){

        int v = e.second, w = e.first;
        if(vis[v]) continue;
        cal(v, 1, w, -1);
        tn = siz[v], rmn = inf, getRt(v, u);
        dfz(rt);
    }
    vis[u] = 0;
}

int main(){

    ios::sync_with_stdio(0); cin.tie(0);
    cin >> n >> L >> W;
    for(int i = 2; i <= n; ++i){

        int u, w; cin >> u >> w;
        G[i].pb({w, u}), G[u].pb({w, i});
    }
    tn = n, rmn = inf, getRt(1, 0);
    dfz(rt);
    ans -= n, ans >>= 1;
    cout << ans << endl;
    return 0;
}
发布了55 篇原创文章 · 获赞 0 · 访问量 1247

猜你喜欢

转载自blog.csdn.net/weixin_44059127/article/details/104074195
今日推荐