- 树(tree)
【警示后人】算法逻辑错误
- @ 2026-10-17 12:17:19
完整代码:
#include<bits/stdc++.h>
using namespace std;
typedef pair<int, int> pii;
const int N = 5e4 + 10;
struct Query{
int id, u, v, c;
}querys[N];
bool cmp(Query q1, Query q2){
if(q1.c == q2.c) return q1.id < q2.id;
return q1.c < q2.c;
}
int n, m, lg[2*N], dep[N], fa[N][18], dis[N][18], ans[N], len[N], g[N][18];
vector<pii> e[N];
void dfs(int u, int father){
dep[u] = dep[father] + 1;
fa[u][0] = father;
for(int i = 1; i <= lg[dep[u]]; i ++){
fa[u][i] = fa[fa[u][i-1]][i-1];
dis[u][i] = dis[u][i - 1] + dis[fa[u][i-1]][i-1];
}
for(int i = 0; i < (int)e[u].size(); i ++){
int v = e[u][i].first, w = e[u][i].second;
if(v == father) continue;
dis[v][0] = w;
len[v] = len[u] + w;
dfs(v, u);
}
}
int lca(int x, int y){
if(dep[x] < dep[y]) swap(x, y);
while(dep[x] > dep[y]){
int h = dep[x] - dep[y];
x = fa[x][lg[h]];
}
if(x == y) return x;
for(int i = lg[dep[x]]; i >= 0; i --){
if(fa[x][i] != fa[y][i]){
x = fa[x][i];
y = fa[y][i];
}
}
return fa[x][0];
}
int getlen(int u, int v, int LCA){
if(LCA == -1) LCA = lca(u, v);
return len[u] + len[v] - 2*len[LCA];
}
int jump1(int u, int v, int c){
int LCA = lca(u, v), cnt = 0, lastu = 0, lastv = 0;
while(1){
cnt++;
lastu = u;
int rest = c;
for(int i = lg[dep[u]]; i >= 0; i --){
if(rest >= dis[u][i]){
rest -= dis[u][i];
u = fa[u][i];
}
}
if(dep[u] <= dep[LCA]){
cnt--;
u = lastu;
break;
}
}
while(1){
cnt++;
lastv = v;
int rest = c;
for(int i = lg[dep[v]]; i >= 0; i --){
if(rest >= dis[v][i]){
rest -= dis[v][i];
v = fa[v][i];
}
}
if(dep[v] <= dep[LCA]){
cnt--;
v = lastv;
break;
}
}
if(u == LCA && v == LCA) return cnt;
else if(c >= getlen(u, v, LCA)) return cnt+1;
else return cnt+2;
}
void init_g(int c){
memset(g, 0, sizeof(g));
for(int j = 1; j <= n; j ++){
int x = j, rest = c;
for(int k = lg[dep[j]]; k >= 0; k --){
if(rest >= dis[x][k]){
rest -= dis[x][k];
x = fa[x][k];
}
}
g[j][0] = x;
for(int k = 1; k <= lg[dep[j]]; k ++){
g[j][k] = g[g[j][k-1]][k-1];
}
}
}
int jump2(int u, int v, int c){
int LCA = lca(u, v), cnt = 0;
for(int i = lg[dep[u]]; i >= 0; i --){
int nxt = g[u][i];
if(dep[nxt] > dep[LCA]){
cnt += (1<<i);
u = nxt;
}
}
for(int i = lg[dep[v]]; i >= 0; i --){
int nxt = g[v][i];
if(dep[nxt] > dep[LCA]){
cnt += (1<<i);
v = nxt;
}
}
if(u == LCA && v == LCA) return cnt;
else if(c >= getlen(u, v, LCA)) return cnt+1;
else return cnt+2;
}
int jump3(int u, int v, int c){
int LCA = lca(u, v), cnt = 0;
for(int i = lg[dep[u]]; i >= 0; i --){
int nxt = g[u][i];
if(dep[nxt] >= dep[LCA]){
cnt += (1<<i);
u = nxt;
}
}
for(int i = lg[dep[v]]; i >= 0; i --){
int nxt = g[v][i];
if(dep[nxt] >= dep[LCA]){
cnt += (1<<i);
v = nxt;
}
}
if(u == LCA && v == LCA) return cnt;
else if(c >= getlen(u, v, LCA)) return cnt+1;
else return cnt+2;
}
int main(){
freopen("tree.in", "r", stdin);
freopen("tree.out", "w", stdout);
ios::sync_with_stdio(0);
for(int i = 2; i <= 2*N - 10; i ++) lg[i] = lg[i>>1] + 1;
cin >> n;
for(int i = 1; i < n; i ++){
int x, y, z;
cin >> x >> y >> z;
e[x].push_back({y, z});
e[y].push_back({x, z});
}
dfs(1, 0);
//将查询离线下来
cin >> m;
for(int i = 1; i <= m; i ++){
int u, v, c;
cin >> u >> v >> c;
querys[i] = {i, u, v, c};
}
sort(querys + 1, querys + m + 1, cmp);
int lastc = 0, Sqrt = (int)floor(sqrt(2*n));
for(int i = 1; i <= m; i ++){
int id = querys[i].id, u = querys[i].u, v = querys[i].v, c = querys[i].c;
if(c > Sqrt){//暴力倍增解决
ans[id] = jump1(u, v, c);
}else{//否则查表倍增解决
if(lastc != querys[i].c){//处理一个新的表,覆盖上一个表
//处理表的总复杂度sqrt(2n)*n*log n,实际至少折成1/4吧
init_g(c);
}
//倍增解决
ans[id] = jump2(u, v, c);
}
lastc = c;
}
for(int i = 1; i <= m; i ++) cout << ans[i] << "\n";
return 0;
}
其中,void jump2() 是正确的,void jump3() 是错误的。它们的区别就在于大于号和大于等于号。
为什么?【未完待续】
0 条评论
目前还没有评论...
信息
- ID
- 2807
- 时间
- ms
- 内存
- MiB
- 难度
- 7
- 标签
- (无)
- 递交数
- 47
- 已通过
- 5
- 上传者