Codeforces 293E
Portal: https://codeforces.com/contest/293/problem/E
Title:
Give you a tree with an edge weight of 0 at the beginning, then give you n-1 operations, add edge weight to the edge every time, ask you how many pairs of paths between n-1 operations are less than or equal to l, and the edge weight is less than or equal to w
Explanation:
poj1741 point divide and conquer problem is edge weight sum less than or equal to k, a limit of path number is added here
For the two restrictions of the path number and the edge weight, we can get two inequalities, and we can get an array a satisfying the distance by using the point divide and conquer.
After sorting array a according to the distance from small to large, it can satisfy the condition of cdq. It is also a three-dimensional partial order problem. When counting, we need to pay attention to the weight.
Code:
#include <set> #include <map> #include <cmath> #include <cstdio> #include <string> #include <vector> #include <cstring> #include <iostream> #include <algorithm> using namespace std; typedef long long LL; typedef pair<int, int> pii; typedef unsigned long long uLL; #define ls rt<<1 #define rs rt<<1|1 #define lson l,mid,rt<<1 #define rson mid+1,r,rt<<1|1 #define bug printf("*********\n") #define FIN freopen("input.txt","r",stdin); #define FON freopen("output.txt","w+",stdout); #define IO ios::sync_with_stdio(false),cin.tie(0) #define debug1(x) cout<<"["<<#x<<" "<<(x)<<"]\n" #define debug2(x,y) cout<<"["<<#x<<" "<<(x)<<" "<<#y<<" "<<(y)<<"]\n" #define debug3(x,y,z) cout<<"["<<#x<<" "<<(x)<<" "<<#y<<" "<<(y)<<" "<<#z<<" "<<z<<"]\n" const int maxn = 3e5 + 5; const int INF = 0x3f3f3f3f; struct node { int x, y; int op; bool operator < (const node &a) const { if(x != a.x) return x < a.x; if(y != a.y) return y < a.y; return op < a.op; } node() {}; node(int _x, int _y, int _op) { x = _x, y = _y, op = _op; } } a[maxn], tmp[maxn]; int cnt; int n, L, W; struct EDGE { int v, w, nxt; } edge[maxn << 1]; int head[maxn]; int tot; void add_edge(int u, int v, int w) { edge[tot].v = v; edge[tot].w = w; edge[tot].nxt = head[u]; head[u] = tot++; } int sz[maxn], vis[maxn], mx[maxn]; int get_root(int u, int fa, int num) { int y = 0; mx[u] = 0; sz[u] = 1; for(int i = head[u]; i != -1; i = edge[i].nxt) { int v = edge[i].v; if(!vis[v] && v != fa) { int z = get_root(v, u, num); // debug3(u, v, z); sz[u] += sz[v]; mx[u] = max(mx[u], sz[v]); if(mx[y] > mx[z]) y = z; } } mx[u] = max(mx[u], num - sz[u]); return mx[u] < mx[y] ? u : y; } void dfs(int u, int fa, int len, int weight) { a[++cnt] = node(len, weight, 0); a[++cnt] = node(L - len, W - weight, 1); for(int i = head[u]; i != -1; i = edge[i].nxt) { int v = edge[i].v; if(!vis[v] && v != fa) { dfs(v, u, len + 1, weight + edge[i].w); } } } LL cdq(int l, int r) { if(l == r) return 0; int mid = (l + r) >> 1; LL ans = cdq(l, mid) + cdq(mid + 1, r); int p = l, q = mid + 1, res = 0; for(int i = l; i <= r; i++) { if((p <= mid && (a[p].y < a[q].y || (a[p].y == a[q].y && a[p].op <= a[q].op))) || q > r) { res += a[p].op ^ 1; tmp[i] = a[p++]; } else { ans += a[q].op * res; tmp[i] = a[q++]; } } for(int i = l; i <= r; i++) { a[i] = tmp[i]; } // debug3(l, r, ans); return ans; } LL Find(int u, int len, int weight) { LL res = 0; cnt = 0; dfs(u, -1, len, weight); sort(a + 1, a + cnt + 1); // for(int i=1;i<=cnt;i++){ // debug3(a[i].x,a[i].y,a[i].op); // } for(int i = 1; i <= cnt; i++) { if(2 * a[i].x <= L && 2 * a[i].y <= W) res += a[i].op ^ 1; } // debug1(cnt); return (cdq(1, cnt) - res) / 2; } LL solve(int u, int num) { int root = get_root(u, -1, num); LL res = Find(root, 0, 0); vis[root] = 1; for(int i = head[root]; i != -1; i = edge[i].nxt) { int v = edge[i].v, w = edge[i].w; if(!vis[v]) { res -= Find(v, 1, w); res += solve(v, sz[v] > sz[root] ? num - sz[root] : sz[v]); } } return res; } int main() { #ifndef ONLINE_JUDGE FIN #endif mx[0] = INF; memset(head, -1, sizeof(head)); tot = 0; scanf("%d%d%d", &n, &L, &W); for(int i = 2; i <= n; i++) { int u, w; scanf("%d%d", &u, &w); add_edge(i, u, w); add_edge(u, i, w); } printf("%lld\n", solve(1, n)); return 0; }