【点分治 树状数组】洛谷 P4178 Tree
2021-07-22 11:30:00 # ACM

题链

首先点分治;
由于求解的是小于等于$k$的个数,于是开一个树状数组维护前缀和即可;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
#include<bits/stdc++.h>
using namespace std;
#define LL long long
#define MAXN 20009
#define MS 40009

int n,m;
struct node{
int to,val;
};
vector<node > vc[MS];
int sz[MS],w[MS];
int rt,tr_size;
int del[MS];
int dis[MS];
int dislist[MS] ,cntd;
int ext[MAXN];
queue<int > Q;
LL ans;
int p[MAXN]; // 树状数组

int lowbit(int x){
return x&(-x);
}

void add(int pos,int val){
for(;pos<=20000;pos+=lowbit(pos)) p[pos] += val;
}

int get_sum(int pos){
int ans = 0;
for(;pos;pos-=lowbit(pos)) ans += p[pos];
return ans;
}

void get_rt(int u,int f){
sz[u] = 1;
w[u] = 0;
for(auto &nb:vc[u]){
int v = nb.to;
if(v != f && !del[v]){
get_rt(v,u);
sz[u] += sz[v];
w[u] = max(w[u],sz[v]);
}
}
w[u] = max(w[u],tr_size-sz[u]);
if(w[u] < w[rt]) rt = u;
}

void get_dis(int u,int f){
if(dis[u] <= m) dislist[++cntd] = dis[u];
for(auto &nb:vc[u]){
int v = nb.to;
int val = nb.val;
if(v != f && !del[v]){
dis[v] = dis[u] + val;
get_dis(v,u);
}
}
}

void cal(int u){
ext[0]++;
add(1,1); // +1方便树状数组维护
for(auto &nb:vc[u]){
int v = nb.to;
int val = nb.val;
if(!del[v]){
cntd = 0;
dis[v] = val;
get_dis(v,u);

for(int i=1;i<=cntd;i++){
ans += get_sum(m-dislist[i]+1); // 树状数组求前缀和
}

for(int i=1;i<=cntd;i++){
ext[dislist[i]]++;
add(dislist[i]+1,1);
Q.push(dislist[i]);
}
}
}
ext[0]--;
add(1,-1);
while(!Q.empty()){
ext[Q.front()]--;
add(Q.front()+1,-1);
Q.pop();
}
}

void divide(int u){
del[u] = 1;
cal(u);
for(auto &nb:vc[u]){
int v = nb.to;
if(!del[v]){
w[rt = 0] = tr_size = sz[v];
get_rt(v,0);
get_rt(rt,0);
divide(rt);
}
}
}

void solve(){
cin >> n;
for(int i=2;i<=n;i++){
int u,v,val;
cin >> u >> v >> val;
vc[u].push_back({v,val});
vc[v].push_back({u,val});
}
cin >> m;
w[rt = 0] = tr_size = n;
get_rt(1,0);
get_rt(rt,0);
divide(rt);

cout << ans << "\n";
}

int main(){
ios::sync_with_stdio(false);
int ce;
// cin >> ce;
ce = 1;
while(ce--){
solve();
}

return 0;
}
Prev
2021-07-22 11:30:00 # ACM
Next