CodeForces 293E Close Vertices 点分治
题意:现在有一棵树,每条边的长度都为1,然后有一个权值,求存在多少个(u,v)点对,他们的路劲长度 <= l, 总权重 <= w.
题解:
1.找到树的重心。
2.求出每个点到中心的长度和权值。
3.对所有点都询问出合法点的个数(包括同一颗子树)加到答案上。
4.对于每一棵子树内部都找到合法点的个数从答案中减去。
5.递归处理每一颗子树。
我们现在最大的问题就是怎么计算合法点的个数。
我们把点的信息记录下来之后,按照权重从小到达排序。
然后我们就可以用2个端点维护出 a[l].weight + a[r].weight <= d
这样对于l来说, [l+1,r]里面的所有点都满足权重的条件了。
然后就只需要询问 [l+1,r]里面的点的深度 <= l - deep[i]的个数了,对于这个个数我们用树状数组去维护这个信息,一开始我们把所有的点的深度都加到树状数组里面,然后每次端点移动位置的时候都把当前点的深度从树状数组中移除,这样我们维护出了一颗[ l+1 , r] 里面的点的深度信息了。
代码:
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define Fopen freopen("_in.txt","r",stdin); freopen("_out.txt","w",stdout); 4 #define LL long long 5 #define ULL unsigned LL 6 #define fi first 7 #define se second 8 #define pb push_back 9 #define lson l,m,rt<<1 10 #define rson m+1,r,rt<<1|1 11 #define lch(x) tr[x].son[0] 12 #define rch(x) tr[x].son[1] 13 #define max3(a,b,c) max(a,max(b,c)) 14 #define min3(a,b,c) min(a,min(b,c)) 15 typedef pair<int,int> pll; 16 const int inf = 0x3f3f3f3f; 17 const LL INF = 0x3f3f3f3f3f3f3f3f; 18 const LL mod = (int)1e9+7; 19 const int N = 5e5 + 100; 20 int n, len, w; 21 int tree[N]; 22 int root, sz[N], mxr; 23 int vis[N]; 24 int head[N], to[N*2], nt[N*2], ct[N*2]; 25 void add(int x, int v){ 26 for(int i = x; i <= n && i; i += i & (-i)) 27 tree[i] += v; 28 } 29 int query(int x){ 30 int ret = 0; 31 for(int i = x; i; i -= i&(-i)) 32 ret += tree[i]; 33 return ret; 34 } 35 void getW(int o, int u, int num){ 36 sz[u] = 1; 37 int mx = 0; 38 for(int i = head[u]; ~i; i = nt[i]){ 39 int v = to[i]; 40 if(vis[v] || v == o) continue; 41 getW(u, v, num); 42 sz[u] += sz[v]; 43 mx = max(mx, sz[v]); 44 } 45 if(o) mx = max(mx, num-sz[u]); 46 if(mx < mxr) mxr = mx, root = u; 47 } 48 //pll p[N]; 49 struct Node { 50 int fi, se; 51 bool operator < (const Node & x) const { 52 if(fi == x.fi) return se < x.se; 53 return fi < x.fi; 54 } 55 }p[N]; 56 LL cal(int l, int r){ 57 if(l >= r) return 0; 58 sort(p+l, p+r+1); 59 LL ans = 0; 60 for(int i = l; i <= r; i++) add(p[i].se, 1); 61 for(int L = l, R = r; L <= R; L++){ 62 while(L < R && p[L].fi + p[R].fi > w) { 63 add(p[R].se, -1); 64 R--; 65 } 66 add(p[L].se, -1); 67 if(L >= R) break; 68 ans += query(max(0, len-p[L].se)); 69 } 70 return ans; 71 } 72 73 int sum = 0; 74 void Dfs(int o, int u, int deep, int w){ 75 sz[u] = 1; 76 ++sum; 77 p[sum].fi = w; 78 p[sum].se = deep; 79 for(int i = head[u]; ~i; i = nt[i]){ 80 int v = to[i]; 81 if(v == o || vis[v]) continue; 82 Dfs(u, v, deep+1, w+ct[i]); 83 sz[u] += sz[v]; 84 } 85 } 86 LL ans = 0; 87 void GG(int id, int num){ 88 if(num == 1){ 89 return ; 90 } 91 mxr = inf; 92 getW(0, id, num); 93 vis[root] = 1; 94 int ls = 1; sum = 0; 95 for(int i = head[root]; ~i; i = nt[i]){ 96 int v = to[i]; 97 if(vis[v]) continue; 98 Dfs(0, to[i], 1, ct[i]); 99 ans -= cal(ls, sum); 100 ls = sum + 1; 101 } 102 sum++; 103 p[sum].fi = p[sum].se = 0; 104 ans += cal(1, sum); 105 //cout << query(n) << endl; 106 for(int i = head[root]; ~i; i = nt[i]){ 107 int v = to[i]; 108 if(vis[v]) continue; 109 GG(v, sz[v]); 110 } 111 } 112 int tot = 0; 113 void add(int u, int v, int w){ 114 to[tot] = v; 115 ct[tot] = w; 116 nt[tot] = head[u]; 117 head[u] = tot++; 118 } 119 int main(){ 120 memset(head, -1, sizeof(head)); 121 scanf("%d%d%d", &n, &len, &w); 122 int u, v, val; 123 for(int i = 2; i <= n; i++){ 124 u = i; 125 scanf("%d%d", &v, &val); 126 add(u, v, val); 127 add(v, u, val); 128 } 129 GG(1, n); 130 printf("%I64d\n", ans); 131 return 0; 132 } 133