[IOI 2011]Race
Description
给一棵树,每条边有非负权.求一条简单路径,权值和等于K,且边的数量最小.N <= 200000, 1 <= K <= 1000000
Input
第一行 两个整数 n, k
第二..n行 每行三个整数 表示一条无向边的两端和权值 (注意点的编号从0开始)
Output
一个整数 表示最小边数量 如果不存在这样的路径 输出-1
Sample Input
4 3
0 1 1
1 2 2
1 3 4
Sample Output
2
题解
做了一上午的狗屎题,其实很水(点分裸题)...老是找不出细节错误....
- 在每一棵点分治的树中只考虑经过根的路径;
- (1)某一点到根的路径
- 只需要算出每个点到根的距离即可判断。
- (2)来自根节点不同儿子所在子树的两个点构成的路径
- 每个点相当于有三个参数$belong[i]$,$dis[i]$,$s[i]$,分别表示删除根后属于哪个联通快,到根的路径长度以及路径上的边数;
- 原问题相当于求$min(s[i]+s[j])$,$belong[i]!=belong[j]$,$dis[i]+dis[j]=k$。
- (1)某一点到根的路径
- 依次处理根的每一棵子树;
- $f[i]$表示已经处理过的子树中到根距离为$i$的点中$s$值最小为多少;
- 当处理下一棵子树时,每个点所能匹配的点到根的距离都是固定的,直接拿出对应的$f$值更新答案即可,然后利用这棵子树更新$f$数组;
- 这样保证了更新答案的两点$belong$值不同,$dis$相加等于$k$,同时直接找出当前最优解。
- 易发现,所有路径都是在这个方法中考虑过的,显然是可行的。
1 //It is made by Awson on 2017.9.20 2 #include <set> 3 #include <map> 4 #include <cmath> 5 #include <ctime> 6 #include <queue> 7 #include <stack> 8 #include <string> 9 #include <cstdio> 10 #include <vector> 11 #include <cstdlib> 12 #include <cstring> 13 #include <iostream> 14 #include <algorithm> 15 #define Min(a, b) ((a) < (b) ? (a) : (b)) 16 #define Max(a, b) ((a) > (b) ? (a) : (b)) 17 #define LL long long 18 using namespace std; 19 const int N = 200000; 20 const int K = 1000000; 21 const int INF = ~0u>>1; 22 23 inline int Read() { 24 int sum = 0; 25 char ch = getchar(); 26 while (ch < '0' || ch > '9') ch = getchar(); 27 while (ch >= '0' && ch <= '9') sum = (sum<<1) + (sum<<3) + ch - 48, ch = getchar(); 28 return sum; 29 } 30 int n, k, u, v, c; 31 struct tt { 32 int to, cost, next; 33 }edge[N*2+5]; 34 int path[N+5], top; 35 int ans = INF; 36 int size[N+5], mxsize[N+5]; 37 bool vis[N+5]; 38 int minsize, root; 39 int f[K+5]; 40 41 inline void add(int u, int v, int c) { 42 edge[++top].to = v; 43 edge[top].cost = c; 44 edge[top].next = path[u]; 45 path[u] = top; 46 } 47 void dfs_size(int u, int fa) { 48 size[u] = 1; 49 mxsize[u] = 0; 50 for (int i = path[u]; i; i = edge[i].next) 51 if ((!vis[edge[i].to]) && edge[i].to != fa) { 52 dfs_size(edge[i].to, u); 53 size[u] += size[edge[i].to]; 54 mxsize[u] = Max(mxsize[u], size[edge[i].to]); 55 } 56 } 57 void dfs_getroot(int r, int u, int fa) { 58 mxsize[u] = Max(mxsize[u], size[r]-size[u]); 59 if (mxsize[u] < minsize) minsize = mxsize[u], root = u; 60 for (int i = path[u]; i; i = edge[i].next) 61 if ((!vis[edge[i].to]) && edge[i].to != fa) 62 dfs_getroot(r, edge[i].to, u); 63 } 64 void dfs_getans(int u, int fa, int cnt, int val) { 65 if (val > k) return; 66 if (val == k) { 67 ans = Min(ans, cnt); 68 return; 69 } 70 int tmp = k-val; 71 if (f[tmp]) ans = Min(f[tmp]+cnt, ans); 72 for (int i = path[u]; i; i = edge[i].next) 73 if ((!vis[edge[i].to]) && edge[i].to != fa) 74 dfs_getans(edge[i].to, u, cnt+1, val+edge[i].cost); 75 } 76 void dfs_update(int u, int fa, int cnt, int val) { 77 if (val >= k) return; 78 if (!f[val]) f[val] = cnt; 79 else f[val] = Min(f[val], cnt); 80 for (int i = path[u]; i; i = edge[i].next) 81 if ((!vis[edge[i].to]) && edge[i].to != fa) 82 dfs_update(edge[i].to, u, cnt+1, val+edge[i].cost); 83 } 84 void dfs_delete(int u, int fa, int val) { 85 if (val >= k) return; 86 f[val] = 0; 87 for (int i = path[u]; i; i = edge[i].next) 88 if ((!vis[edge[i].to]) && edge[i].to != fa) 89 dfs_delete(edge[i].to, u, val+edge[i].cost); 90 } 91 void solve(int x) { 92 minsize = INF; 93 dfs_size(x, 0); 94 dfs_getroot(x, x, 0); 95 vis[root] = true; 96 for (int i = path[root]; i; i = edge[i].next) 97 if (!vis[edge[i].to]) { 98 dfs_getans(edge[i].to, root, 1, edge[i].cost); 99 dfs_update(edge[i].to, root, 1, edge[i].cost); 100 } 101 for (int i = path[root]; i; i = edge[i].next) 102 if (!vis[edge[i].to]) 103 dfs_delete(edge[i].to, root, edge[i].cost); 104 for (int i = path[root]; i; i = edge[i].next) 105 if (!vis[edge[i].to]) 106 solve(edge[i].to); 107 } 108 void work() { 109 for (int i = 1; i < n; i++) { 110 u = Read(); v = Read(); c = Read(); 111 u++, v++; 112 add(u, v, c); 113 add(v, u, c); 114 } 115 ans = INF; 116 solve(1); 117 printf("%d\n", ans == INF ? -1 : ans); 118 } 119 int main() { 120 int size = 128 << 20; //==========// 121 char *p = (char*)malloc(size) + size; //手 动 扩 栈// 122 __asm__("movl %0, %%esp\n" :: "r"(p)); //==========// 123 n = Read(); k = Read(); 124 work();return 0; 125 }
博主蒟蒻,随意转载。但必须附上原文链接:http://www.cnblogs.com/NaVi-Awson/,否则你会终生找不到妹子!!!
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步