CodeForces

来源:互联网 发布:彩弹枪淘宝有么 编辑:程序博客网 时间:2024/06/02 00:23

题意:

一棵树上 告诉你边权。

问你有多少点对满足的路上的权值之和 小于等于w, 边数小于等于L。

思路:

显然树上的点分治。

和男人八题一样, 只不过多加了一个边数小于等于L的限制。(一维限制变成二维限制)

做法肯定还是一样。

只不过在求经过重心满足要求点对时有点变化 (其余算法 看上一篇文章)。。


分析一下, 因为边权最大1e9, 边数最大1e5 , 因此, 边数这一个限制,我们可以用数据结构干掉。

因此按照边权w 从小到大排序。

初始状态 把所有的边数 加到 线段树里或者树状数组里, 然后双指针在移动时,  移动一个删一个。

双指针里肯定是边权符合要求的, 要想边数也符合, 直接数据结构查询即可。


注意:

分治的时候就不能在分治一次初始化数据结构一次了。  TLE了两发T_T

分析一下, 初始化数据结构肯定时o(nlogn)的  ,最后双指针肯定移动到一块去, 因此  最后数据结构里最多只有  最后指针那个位置不为空。  log n 删一下即可。

吐槽:

能用树状数组就别用线段树, 慢的两倍多= =!!!!

#include <cstdio>#include <cstring>#include <algorithm>#include <vector>using namespace std;const int maxn = 100000 + 10;int n, l;long long w;vector<pair<int,int> >g[maxn];long long ans;int vis[maxn];int siz[maxn];int mx[maxn];///=======================/// 树状数组int c[maxn];inline int lowbit(int x){    return x&-x;}int SUM(int x){    int ans = 0;    while(x){        ans += c[x];        x -= lowbit(x);    }    return ans;}void ADD(int x,int add){    while(x <= l+1){        c[x] += add;        x += lowbit(x);    }}///=======================void getsize(int cur,int fa){    siz[cur] = 1;    mx[cur] = 0;    for (int i = 0; i < g[cur].size(); ++i){        int v = g[cur][i].first;        if (v != fa && !vis[v]){            getsize(v, cur);            siz[cur] += siz[v];            if (siz[v] > mx[cur]){                mx[cur] = siz[v];            }        }    }}int root, mi;void find(int rt, int cur,int fa){ /// 找以rt 为根的树的重心。    mx[cur] = max(mx[cur], siz[rt] - siz[cur]);    if (mx[cur] < mi){        mi = mx[cur];        root = cur;    }    for (int i = 0; i < g[cur].size(); ++i){        int v = g[cur][i].first;        if (v != fa && !vis[v]){            find(rt, v, cur);        }    }}struct node{ /// 距离变成了一个二维的偏序关系。    long long d1;    int d2;    node(long long d1 = 0,int d2 = 0):d1(d1), d2(d2){}};bool cmp(node a, node b){ /// 按边权排序    return a.d1 < b.d1;}node dis[maxn];int cnt;void getdis(int cur,long long d1, int d2, int fa){    dis[cnt++] = node(d1, d2);    for (int i = 0; i < g[cur].size(); ++i){        int v = g[cur][i].first;        int w = g[cur][i].second;        if (v != fa && !vis[v]){            getdis(v, d1 + w, d2 + 1, cur);        }    }}long long solve(int cur,long long d1,int d2){    long long ret = 0;    cnt = 0;    getdis(cur, d1, d2, 0);    sort(dis, dis + cnt, cmp);//    memset(c,0,sizeof c);    int i = 0, j = cnt - 1;    for (int i = 0; i < cnt; ++i){        ADD(dis[i].d2+1, 1);    }    while(i < j){        ADD(dis[i].d2+1, -1);        while(i < j && dis[i].d1 + dis[j].d1 > w){            ADD(dis[j].d2+1, -1);            --j;        }        if (l - dis[i].d2 >= 0){            int tmp = SUM(l-dis[i].d2+1);            ret += tmp;        }        ++i;    }    if (SUM(dis[j].d2 + 1))ADD(dis[j].d2+1,-1); /// *****只需要特判一下 就可以完全清空树状数组,不能memset, 会超时!!!    return ret;}const int inf = 0x3f3f3f3f;void dfs(int cur){    getsize(cur, 0);    mi = inf;    find(cur, cur, 0);    ans += solve(root, 0, 0);//    printf("root = %d\n", root);    vis[root] = 1;    int tmproot = root;    for (int i = 0; i < g[tmproot].size(); ++i){        int v = g[tmproot][i].first;        int w = g[tmproot][i].second;        if (!vis[v]){            ans -= solve(v, w, 1);            dfs(v);        }    }}int main(){    scanf("%d %d %lld", &n, &l, &w);    for (int i = 1; i < n; ++i){        int x,y;        scanf("%d %d",&x, &y);        g[x].push_back(make_pair(i+1, y));        g[i+1].push_back(make_pair(x, y));    }    dfs(1);    printf("%lld\n", ans);    return 0;}


E. Close Vertices
time limit per test
5 seconds
memory limit per test
256 megabytes
input
standard input
output
standard output

You've got a weighted tree, consisting of n vertices. Each edge has a non-negative weight. The length of the path between any two vertices of the tree is the number of edges in the path. The weight of the path is the total weight of all edges it contains.

Two vertices are close if there exists a path of length at most l between them and a path of weight at most w between them. Count the number of pairs of vertices v, u (v < u), such that vertices v and u are close.

Input

The first line contains three integers nl and w (1 ≤ n ≤ 105, 1 ≤ l ≤ n, 0 ≤ w ≤ 109). The next n - 1 lines contain the descriptions of the tree edges. The i-th line contains two integers pi, wi (1 ≤ pi < (i + 1), 0 ≤ wi ≤ 104), that mean that the i-th edge connects vertex (i + 1)and pi and has weight wi.

Consider the tree vertices indexed from 1 to n in some way.

Output

Print a single integer — the number of close pairs.

Please, do not use the %lld specifier to read or write 64-bit integers in С++. It is preferred to use the cincout streams or the %I64dspecifier.

Examples
input
4 4 61 31 41 3
output
4
input
6 2 171 32 52 131 65 9
output
9


原创粉丝点击