题目背景
感谢 hzwer 的点分治互测。
题目描述
给定一棵有 nn 个点的树,询问树上距离为 kk 的点对是否存在。
输入格式
第一行两个数 n,mn,m。
第 22 到第 nn 行,每行三个整数 u, v, wu,v,w,代表树上存在一条连接 uu 和 vv 边权为 ww 的路径。
接下来 mm 行,每行一个整数 kk,代表一次询问。
输出格式
对于每次询问输出一行一个字符串代表答案,存在输出 AYE
,否则输出 NAY
。
输入输出样例
输入 #1复制
2 1 1 2 2 2
输出 #1复制
AYE
说明/提示
数据规模与约定
- 对于 30\%30% 的数据,保证 n\leq 100n≤100。
- 对于 60\%60% 的数据,保证 n\leq 1000n≤1000,m\leq 50m≤50 。
- 对于 100\%100% 的数据,保证 1 \leq n\leq 10^41≤n≤104,1 \leq m\leq 1001≤m≤100,1 \leq k \leq 10^71≤k≤107,1 \leq u, v \leq n1≤u,v≤n,1 \leq w \leq 10^41≤w≤104。
提示
- 本题不卡常。
- 如果您 #7 一直 RE/TLE,不妨看看 这个帖子。
请注意,第一篇题解也存在帖子中说明的问题,但是鉴于此问题与点分治算法本身无关,并且题解质量非常高,因此暂不撤下题解,仅供参考。
根据b站AgOH代码改写
实现离线非n2操作
#include<bits/stdc++.h>
const int maxn = 1e5 + 5;
const int maxm = 1e7 + 5;
const int limit = 1e7;
using namespace std;
vector<pair<int, int>> G[maxn];
int n, m, rt, sum, cnt, q[maxn];
int tmp[maxn], siz[maxn], dis[maxn], maxp[maxn];
bool judge[maxm], ans[maxm], vis[maxm];
void getrt(int x, int f){
siz[x] = 1;
maxp[x] = 0;
for(auto i : G[x]){
if(vis[i.first] || i.first == f)
continue;
getrt(i.first, x);
siz[x] += siz[i.first];
if(siz[i.first] > maxp[x])
maxp[x] = siz[i.first];
}
maxp[x] = max(maxp[x], sum - siz[x]);
if(maxp[x] < maxp[rt]) rt = x;
}
void getdis(int x, int f){
if(dis[x] <= limit) tmp[cnt++] = dis[x];
for(auto i : G[x]){
if(i.first == f || vis[i.first])
continue;
dis[i.first] = dis[x] + i.second;
getdis(i.first, x);
}
}
void solve(int x){
queue<int> Q;
for(auto i : G[x]){
if(vis[i.first])
continue;
cnt = 0;
dis[i.first] = i.second;
getdis(i.first, x);
for(int j = 0; j < cnt; j++)
for(int k = 0; k < m; k++)
if(q[k] >= tmp[j])
ans[k] |= judge[q[k] - tmp[j]];
for(int j = 0; j < cnt; j++){
Q.push(tmp[j]);
judge[tmp[j]] = 1;
}
}
while(!Q.empty()){
judge[Q.front()] = 0;
Q.pop();
}
}
void divide(int x){
vis[x] = judge[0] = 1;
solve(x);
for(auto i : G[x]){
if(vis[i.first])
continue;
maxp[rt = 0] = sum = siz[i.first];
getrt(i.first, 0);
getrt(rt, 0);
divide(rt);
}
}
int main(){
ios::sync_with_stdio(0);
cin >> n >> m;
for(int i = 1; i < n; i++){
int a, b, c;
cin >> a >> b >> c;
G[a].push_back({b, c});
G[b].push_back({a, c});
}
for(int i = 0; i < m; i++)
cin >> q[i];
maxp[0] = sum = n;
getrt(1, 0);
getrt(rt, 0);
divide(rt);
for(int i = 0; i < m; i++){
if(ans[i])
cout << "AYE" << endl;
else
cout << "NAY" << endl;
}
}