砍树
Posted onlyblues
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了砍树相关的知识,希望对你有一定的参考价值。
砍树
给定一棵由 $n$ 个结点组成的树以及 $m$ 个不重复的无序数对 $(a_1,b_1),(a_2,b_2), \\ldots ,(a_m,b_m)$,其中 $a_i$ 互不相同,$b_i$ 互不相同,$a_i \\ne b_j \\ (1 \\leq i,j \\leq m)$。
小明想知道是否能够选择一条树上的边砍断,使得对于每个 $(a_i,b_i)$ 满足 $a_i$ 和 $b_i$ 不连通,如果可以则输出应该断掉的边的编号(编号按输入顺序从 $1$ 开始),否则输出 $−1$。
输入格式
输入共 $n+m$ 行,第一行为两个正整数 $n,m$。
后面 $n−1$ 行,每行两个正整数 $x_i,y_i$ 表示第 $i$ 条边的两个端点。
后面 $m$ 行,每行两个正整数 $a_i,b_i$。
输出格式
一行一个整数,表示答案,如有多个答案,输出编号最大的一个。
数据范围
对于 $30\\%$ 的数据,保证 $1 < n \\leq 1000$。
对于 $100\\%$ 的数据,保证 $1 < n \\leq 10^5$,$1 \\leq m \\leq \\fracn2$。
输入样例:
6 2 1 2 2 3 4 3 2 5 6 5 3 6 4 5
输出样例:
4
样例解释
断开第 $2$ 条边后形成两个连通块:$\\3,4\\$,$\\1,2,5,6\\$,满足 $3$ 和 $6$ 不连通,$4$ 和 $5$ 不连通。
断开第 $4$ 条边后形成两个连通块:$\\1,2,3,4\\$,$\\5,6\\$,同样满足 $3$ 和 $6$ 不连通,$4$ 和 $5$ 不连通。
$4$ 编号更大,因此答案为 $4$。
解题思路
由于在树中任意两点间的路径是固定的,因此要使得数对$(a_i,b_i)$对应的两个点不连通,那么只需要把$a_i \\to b_i$路径上的任意一条边砍掉即可。因此可以枚举所有的数对$(a_i,b_i)$,并对$a_i \\to b_i$路径上的所有边都累加$1$,表示砍掉这条边可以使得一个数对不连通。最后只需要遍历树中所有边找出被累加了$m$次的边并找到最大的编号。
由于需要对树中某条路径上的边都加上某个数,因此需要用到树上差分中的边差分,关于树上差分的简单介绍可以参考链接。同时还需要用哈希表存边$(a_i,b_i)$与编号的映射,为了避免使用 std::map 这里把二元组$(a_i,b_i)$映射为$a_i \\times 100001 + b_i$,由于$b_i \\leq 10^5$因此$P$取到$100001$,相当于把$P$进制数转换为十进制数。然后再用 std::unordered_map 来存边与编号的映射关系。当然如果是cf的题还是老老实实用 std::map 吧(悲。
AC代码如下,时间复杂度为$O(n + m \\logn)$:
#include <bits/stdc++.h> using namespace std; typedef long long LL; const int N = 1e5 + 10, M = N * 2; int n, m; int head[N], e[M], ne[M], idx; int fa[N][17], dep[N]; int q[N], hh, tt = -1; unordered_map<LL, int> mp; int d[N]; int ans = -1; void add(int v, int w) e[idx] = w, ne[idx] = head[v], head[v] = idx++; LL get(int x, int y) return x * 100001ll + y; int lca(int a, int b) if (dep[a] < dep[b]) swap(a, b); for (int i = 16; i >= 0; i--) if (dep[fa[a][i]] >= dep[b]) a = fa[a][i]; if (a == b) return a; for (int i = 16; i >= 0; i--) if (fa[a][i] != fa[b][i]) a = fa[a][i], b = fa[b][i]; return fa[a][0]; void dfs(int u, int pre) for (int i = head[u]; i != -1; i = ne[i]) if (e[i] != pre) dfs(e[i], u); d[u] += d[e[i]]; if (pre != -1 && d[u] == m) ans = max(ans, mp[get(u, pre)]); int main() scanf("%d %d", &n, &m); memset(head, -1, sizeof(head)); for (int i = 1; i < n; i++) int v, w; scanf("%d %d", &v, &w); add(v, w), add(w, v); mp[get(v, w)] = mp[get(w, v)] = i; memset(dep, 0x3f, sizeof(dep)); dep[0] = 0, dep[1] = 1; q[++tt] = 1; while (hh <= tt) int t = q[hh++]; for (int i = head[t]; i != -1; i = ne[i]) if (dep[e[i]] > dep[t] + 1) dep[e[i]] = dep[t] + 1; q[++tt] = e[i]; fa[e[i]][0] = t; for (int j = 1; j <= 16; j++) fa[e[i]][j] = fa[fa[e[i]][j - 1]][j - 1]; for (int i = 0; i < m; i++) int a, b; scanf("%d %d", &a, &b); d[a]++, d[b]++, d[lca(a, b)] -= 2; dfs(1, -1); printf("%d", ans); return 0;
本文来自博客园,作者:onlyblues,转载请注明原文链接:https://www.cnblogs.com/onlyblues/p/17363557.html
cogs luogu 砍树
eko.in
输出文件:eko.out
简单对比时间限制:1 s 内存限制:256 MB
【题目描述】
N棵树,每棵都有一个整数高度。有一个木头的总需要量M。
现在确定一个最大的统一的砍树高度H,如果某棵树的高度大于H,则高出的部分被砍下。使得所有被砍下的木材长度之和达到M(允许稍超过M)。
例如,有4棵树,高度分别是20 15 10 17, 需要的木材长度为 7,砍树高度为15时,第1棵树被砍下5,第4棵树被砍下2,得到的总长度为7。如果砍树高度为16时,第1棵树被砍下4,第4棵树被砍下1,则得到的木材数量为5。
【输入格式】
第1行:2个整数N和M,N表示树木的数量(1 ≤ N ≤ 1 000 000),M表示需要的木材总长度(1 ≤ M ≤ 2 000 000 000)。
第2行: N个整数表示每棵树的高度,值均不超过1 000 000 000。所有木材高度之和大于M,因此必然有解。
【输出格式】
第1行:1个整数,表示砍树的最高高度。
【样例输入】
5 20 4 42 40 26 46
【样例输出】
36
1 #include<iostream> 2 #include<cstdio> 3 4 #define ll long long 5 using namespace std; 6 const int N=1000010; 7 8 ll a[N]; 9 ll n,m; 10 11 inline ll read() 12 { 13 ll x=0; 14 char c=getchar(); 15 while(c<‘0‘||c>‘9‘)c=getchar(); 16 while(c>=‘0‘&&c<=‘9‘)x=x*10+c-‘0‘,c=getchar(); 17 return x; 18 } 19 20 inline bool pd(int now) 21 { 22 ll answer=0; 23 for(int i=1;i<=n;i++) 24 if(a[i]-now>0)answer+=(a[i]-now); 25 if(answer>=m)return 1; 26 else return 0; 27 } 28 29 int main() 30 { 31 freopen("eko.in","r",stdin); 32 freopen("eko.out","w",stdout); 33 n=read(); 34 m=read(); 35 ll r=-1; 36 for(int i=1;i<=n;i++) 37 { 38 a[i]=read(); 39 r=max(r,a[i]); 40 } 41 42 ll l=1; 43 ll mid; 44 while(l<r) 45 { 46 mid=(r-l)/2+l; 47 if(pd(mid))l=mid+1; 48 else r=mid; 49 } 50 printf("%lld",l-1); 51 return 0; 52 }
以上是关于砍树的主要内容,如果未能解决你的问题,请参考以下文章