发一个水题。。证明我还活着。。。
题意
给出一棵边权互不相同且根为1的树,并给出q次询问,每次询问给出一个x,问,从根出发,只能往儿子走,每次会选择不超过x的最大的边走下去,如果不存在儿子或者不存在这样的边,则停止,问最终会停在哪个点,将所有询问的答案求和输出。
题解:
无脑一把梭题解 :离线,然后LCT,没了。
暴力题解:离线,从小到大把边插入树中,每次插边的时候,如果近根点已经有了一个儿子边,那么把它删掉,然后把新边插入进去,也就是说存活的边组成了若干不想交的链。这样我们只需要求得每次插入边之后,从根出发的路径延伸到哪里就可以每次log(二分边权)回答询问了。然后想一下。。。每条边被插入一次,删除一次,删除之后,整个子树都没了。然后就暴力维护暴力爬就完事了。。。因为一条边最多被爬到两次:一次是爬下去,一次是整个子树被删掉的时候爬上来。。。这部分是纯线性的。不懂为什么5s。
Code:
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef long long ll;
typedef vector<int> vi;
typedef vector<ll> vl;
typedef long double db;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;
#define PB(x) push_back(x)
#define rep(i,l,r) for (ll i = l,_ = r;i< _;i++)
#define leave(x) do {cout<<#x<<endl;fflush(stdout);return 0;}while (0);
/************* header ******************/
const int maxn = 1e5+100;
int first[maxn],nxt[maxn*2],des[maxn*2],dep[maxn],tot;
int father[maxn];
struct Edge{
int u,v,len;
};
int son[maxn];
int ans[maxn];
bool used[maxn];
vector<Edge> edges;
int n,q;
bool cmp(const Edge &x,const Edge &y){
return x.len < y.len;
}
void clear(){
edges.clear();
for (int i=1;i<=n;i++){
son[i] = 0;
first[i] = 0;
used[i] = 0;
ans[i] = 0;
}
tot =0;
}
inline void addEdge(int x,int y,int z){
tot ++;
des[tot] = y;
nxt[tot] = first[x];
first[x] = tot;
}
void dfs(int node,int fa){
father[node] = fa;
dep[node] = dep[fa] +1;
for (int t = first[node];t;t=nxt[t]){
int v = des[t];
if (v == fa)continue;
dfs(v,node);
}
}
void solve(){
scanf("%d%d",&n,&q);
clear();
for (int i=1;i<n;i++){
int x,y,z;
scanf("%d%d%d",&x,&y,&z);
addEdge(x,y,z);
addEdge(y,x,z);
edges.push_back({x,y,z});
}
dfs(1,0);
sort(edges.begin(),edges.end(),cmp);
int now = 1;
used[1] = 1;
for (int i=0;i<edges.size();i++){
Edge & edge = edges[i];
int x = edge.u;
int y = edge.v;
if (dep[x] > dep[y])swap(x,y);
if (used[x]){
while (now != x){
used[now] = 0;
now = father[now];
}
}
son[x] = y;
while (son[now]){
now = son[now];
used[now] = 1;
}
ans[i] = now;
}
ll out = 0;
while (q--){
int x;
scanf("%d",&x);
int index = lower_bound(edges.begin(),edges.end(),(Edge){0,0,x},cmp) - edges.begin();
if (index >= edges.size() || edges[index].len >= x){
index --;
}
int temp_ans =0;
if (index == -1){
temp_ans =1;
}else{
temp_ans = ans[index];
}
//cout<<temp_ans<<endl;
out += temp_ans;
}
cout<<out<<endl;
}
int main(){
int T;
for (scanf("%d",&T);T;T--){
solve();
}
return 0;
}