Acwing 252. 树
Posted Jozky86
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Acwing 252. 树相关的知识,希望对你有一定的参考价值。
题意:
给定一个有 N 个点(编号 0,1,…,N−1)的树,每条边都有一个权值(不超过 1000)。
树上两个节点 x 与 y 之间的路径长度就是路径上各条边的权值之和。
求长度不超过 K 的路径有多少条。
1≤N≤104,
1≤K≤5×106,
0≤l≤103
题解:
P4178 Tree,和这个题题意是一样的,但是本题的数据范围更大,本题k<=5e6,且空间只给了10MB,树状数组的方法是不行,需要用容斥
我们cal直接记录以u为出发点的所有路径长度,用数组d来存,对数组d排序,然后利用尺取的方法来确定有多少对长度之和小于k。但是这样是会造成重复的
对于图中绿色两点,其路径应该是紫色线,但是我们在计算u时会将红色部分也计算进去,因此我们要将多余部分删去,对于u的儿子节点v,我们计算一遍以v为出发点的路径(还要额外加上边长dis(u,v) ),有多少对长度之和小于k,相当于绿线部分,然后减去绿线部分,相当于将多余部分删去
代码:
#include <bits/stdc++.h>
#include <unordered_map>
#define debug(a, b) printf("%s = %d\\n", a, b);
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> PII;
clock_t startTime, endTime;
//Fe~Jozky
const ll INF_ll= 1e18;
const int INF_int= 0x3f3f3f3f;
void read(){};
template <typename _Tp, typename... _Tps> void read(_Tp& x, _Tps&... Ar)
{
x= 0;
char c= getchar();
bool flag= 0;
while (c < '0' || c > '9')
flag|= (c == '-'), c= getchar();
while (c >= '0' && c <= '9')
x= (x << 3) + (x << 1) + (c ^ 48), c= getchar();
if (flag)
x= -x;
read(Ar...);
}
template <typename T> inline void write(T x)
{
if (x < 0) {
x= ~(x - 1);
putchar('-');
}
if (x > 9)
write(x / 10);
putchar(x % 10 + '0');
}
void rd_test()
{
#ifdef LOCAL
startTime= clock();
freopen("in.txt", "r", stdin);
#endif
}
void Time_test()
{
#ifdef LOCAL
endTime= clock();
printf("\\nRun Time:%lfs\\n", (double)(endTime - startTime) / CLOCKS_PER_SEC);
#endif
}
const int maxn= 1e5 + 9;
int n, k;
vector<PII> vec[maxn];
int vis[maxn];
int rt, cnt;
int sz[maxn], d[maxn];
void dfs_rt(int u, int fa, int tot)
{
sz[u]= 1;
int maxx= 0;
for (auto it : vec[u]) {
int v= it.first;
int w= it.second;
if (v == fa || vis[v])
continue;
dfs_rt(v, u, tot);
sz[u]+= sz[v];
maxx= max(maxx, sz[v]);
}
maxx= max(maxx, tot - sz[u]);
if (2 * maxx <= tot)
rt= u;
}
void dfs_dis(int u, int fa, int dis)
{
d[++cnt]= dis; //记录了所有路径长度
for (auto it : vec[u]) {
int v= it.first;
int w= it.second;
if (v == fa || vis[v])
continue;
dfs_dis(v, u, dis + w);
}
}
int calc(int u, int w)
{
cnt= 0;
dfs_dis(u, 0, w);
sort(d + 1, d + 1 + cnt);
int l= 1, r= cnt, ans= 0;
while (l < r) {
while (d[l] + d[r] > k && l < r)
r--;
/*
d是递增的,当d[l]+d[r]<=k时,此后所有r到l这段都是小于k的
*/
ans+= (r - l);
l++;
}
return ans;
}
int solve(int u, int fa, int tot)
{
dfs_rt(u, fa, tot);
u= rt;
vis[u]= 1;
int res= calc(u, 0);
for (auto it : vec[u]) {
int v= it.first;
int w= it.second;
if (vis[v])
continue;
res-= calc(v, w);
res+= solve(v, u, cnt);
}
return res;
}
int main()
{
//rd_test();
while (1) {
read(n, k);
if (!n && !k)
break;
for (int i= 1; i <= n; i++)
vec[i].clear();
for (int i= 1; i <= n; i++)
vis[i]= 0;
int u, v, w;
for (int i= 1; i < n; i++) {
read(u, v, w);
u++;
v++;
vec[u].push_back({v, w});
vec[v].push_back({u, w});
}
printf("%d\\n", solve(1, 0, n));
}
return 0;
//Time_test();
}
以上是关于Acwing 252. 树的主要内容,如果未能解决你的问题,请参考以下文章
AcWing 1264. 动态求连续区间和(线段树区间查询模板)
AcWing 859. Kruskal算法求最小生成树(稀疏图)