生活随笔
收集整理的這篇文章主要介紹了
【点分治】Tree(luogu 4178/金牌导航 点分治-1)
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
Tree
luogu 4178
金牌導航 點分治-1
題目大意
給出一棵樹,問你書中路徑長度小于等于k的點對個數有多少個
輸入樣例
5
1 2 3
1 3 1
1 4 2
3 5 1
4
輸出樣例
8
數據范圍
1?N?4×1041\leqslant N \leqslant 4\times 10^41?N?4×104
解題思路
對于該樹,求出dfs求出重心
對于兩點都在同一子樹中的點對,分治處理即可
而對于兩點不在同一子樹的
可以先求出重心到所有點的距離,然后排個序,用雙指針得出長度小于k的數量
但是這樣得出來的點對可能在同一子樹中(圖如下)
對于這種情況,我們計算一遍子樹的,然后減去就行了(對于在2的同一子樹中的情況,2中有出現,1中也有出現,所以2就不用再減子樹的點對數了)
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define ll long long
#define N 40010
using namespace std
;
int n
, k
, x
, y
, z
, l
, r
, h
, qn
, sum
, tot
, ans
, s
[N
], p
[N
], q
[N
], mx
[N
], size
[N
], head
[N
];
struct rec
{int to
, l
, next
;
}a
[N
<<1];
void add(int x
, int y
, int z
)
{a
[++tot
].to
= y
;a
[tot
].l
= z
;;a
[tot
].next
= head
[x
];head
[x
] = tot
;
}
void dfs1(int x
)
{p
[x
] = 1;size
[x
] = 1;for (int i
= head
[x
]; i
; i
= a
[i
].next
)if (!p
[a
[i
].to
]){dfs1(a
[i
].to
);size
[x
] += size
[a
[i
].to
];mx
[x
] = max(mx
[x
], size
[a
[i
].to
]);}p
[x
] = 0;mx
[x
] = max(mx
[x
], sum
- size
[x
]);if (mx
[x
] <= mx
[h
]) h
= x
;return;
}
void dfs2(int x
)
{q
[++qn
] = s
[x
];p
[x
] = 1;for (int i
= head
[x
]; i
; i
= a
[i
].next
)if (!p
[a
[i
].to
]){s
[a
[i
].to
] = s
[x
] + a
[i
].l
;dfs2(a
[i
].to
);}p
[x
] = 0;
}
int count(int x
, int y
)
{int sum
= 0;s
[x
] = y
;qn
= 0;dfs2(x
);sort(q
+ 1, q
+ 1 + qn
);l
= 1;r
= qn
;while(l
< r
){while(q
[l
] + q
[r
] > k
&& l
< r
) r
--;sum
+= r
- l
;l
++;}return sum
;
}
void solve(int x
)
{h
= 0;mx
[0] = n
;dfs1(x
);int G
= h
;ans
+= count(G
, 0);p
[G
] = 1;for (int i
= head
[G
]; i
; i
= a
[i
].next
)if (!p
[a
[i
].to
]) ans
-= count(a
[i
].to
, a
[i
].l
);for (int i
= head
[G
]; i
; i
= a
[i
].next
)if (!p
[a
[i
].to
]) sum
= size
[a
[i
].to
], solve(a
[i
].to
);
}
int main()
{scanf("%d", &n
);for (int i
= 1; i
< n
; ++i
){scanf("%d%d%d", &x
, &y
, &z
);add(x
, y
, z
);add(y
, x
, z
); }scanf("%d", &k
);sum
= n
;solve(1);printf("%d", ans
);return 0;
}
總結
以上是生活随笔為你收集整理的【点分治】Tree(luogu 4178/金牌导航 点分治-1)的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。