博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
P4149 [IOI2011]Race
阅读量:5125 次
发布时间:2019-06-13

本文共 3004 字,大约阅读时间需要 10 分钟。

\(\color{#0066ff}{题目描述}\)

给一棵树,每条边有权。求一条简单路径,权值和等于 K,且边的数量最小。

\(\color{#0066ff}{输入格式}\)

第一行:两个整数 n,k。

第二至 n 行:每行三个整数,表示一条无向边的两端和权值 (注意点的编号从 0 开始)

\(\color{#0066ff}{输出格式}\)

一个整数,表示最小边数量。

如果不存在这样的路径,输出 -1。

\(\color{#0066ff}{输入样例}\)

4 30 1 11 2 21 3 4

\(\color{#0066ff}{输出样例}\)

2

\(\color{#0066ff}{数据范围与提示}\)

n≤200000,K≤1000000。

\(\color{#0066ff}{题解}\)

点分治

每次选出重心,对子树进行操作

搜每棵子树,把所有的dis和dep放进一个数组里(pair存)

开一个数组t,t[i]代表,到当前重心的距离为i的最少边数

每次搜完一棵子树,就用t和当前的结果更新ans

然后把当前子树的信息加入t

每次work的时候要把t清空(赋成极大值)

#include
using namespace std;#define LL long longLL in() { char ch; int x = 0, f = 1; while(!isdigit(ch = getchar()))(ch == '-') && (f = -f); for(x = ch ^ 48; isdigit(ch = getchar()); x = (x << 1) + (x << 3) + (ch ^ 48)); return x * f;}struct node { int to, dis; node *nxt; node(int to = 0, int dis = 0, node *nxt = NULL): to(to), dis(dis), nxt(nxt) {} void *operator new (size_t) { static node *S = NULL, *T = NULL; return (S == T) && (T = (S = new node[1024]) + 1024), S++; }};const int N = 2e5 + 10;const int M = 1e6 + 10;const int inf = 0x7f7f7f7f;int siz[N], t[M], f[N], tmp[N];using std::pair;using std::make_pair;pair
ls[N];node *head[N];bool vis[N];int n, k, num, sum, root, cnt;int ans = inf;void add(int from, int to, int dis) { head[from] = new node(to, dis, head[from]);}void getdis(int x, int fa, int dis, int dep) { ls[++cnt] = make_pair(dis, dep); tmp[++num] = dis; for(node *i = head[x]; i; i = i->nxt) if(i->to != fa && !vis[i->to]) getdis(i->to, x, dis + i->dis, dep + 1);}void getroot(int x, int fa) { f[x] = 0; siz[x] = 1; for(node *i = head[x]; i; i = i->nxt) { if(i->to == fa || vis[i->to]) continue; getroot(i->to, x); siz[x] += siz[i->to]; f[x] = std::max(f[x], siz[i->to]); } f[x] = std::max(f[x], sum - siz[x]); if(f[x] < f[root]) root = x;}void calc(int x) { num = 0; for(node *i = head[x]; i; i = i->nxt) { if(vis[i->to]) continue; cnt = 0; getdis(i->to, 0, i->dis, 1); for(int j = 1; j <= cnt; j++) if(ls[j].first <= k) ans = std::min(ans, ls[j].second + t[k - ls[j].first]); for(int j = 1; j <= cnt; j++) if(ls[j].first <= k) t[ls[j].first] = std::min(t[ls[j].first], ls[j].second); } for(int i = 1; i <= num; i++) if(tmp[i] <= k) t[tmp[i]] = inf;}void work(int x) { vis[x] = true; calc(x); for(node *i = head[x]; i; i = i->nxt) { if(vis[i->to]) continue; root = 0, sum = siz[i->to]; getroot(i->to, 0); work(root); }}int main() { n = in(), k = in(); int x, y, z; for(int i = 1; i < n; i++) { x = in(), y = in(), z = in(); add(x + 1, y + 1, z), add(y + 1, x + 1, z); } for(int i = 1; i <= k; i++) t[i] = inf; f[0] = sum = n; getroot(1, 0); work(root); printf("%d", ans == inf? -1 : ans); return 0;}

转载于:https://www.cnblogs.com/olinr/p/10208298.html

你可能感兴趣的文章
[转载]析构函数的虚析构和非虚析构调用的差别
查看>>
Selenium 自动化测试基础知识
查看>>
讲座感悟
查看>>
67. Plus One
查看>>
靠谱的Pycharm安装详细教程
查看>>
001. Ansible简介
查看>>
asp.net core利用DI实现自定义用户系统,脱离ControllerBase.User
查看>>
Redis缓存连接池管理
查看>>
mac brew 安装php扩展报错:parent directory is world writable but not sticky
查看>>
大型网站架构演化发展历程
查看>>
四、COSMIC功能点实操
查看>>
Oracle 数据库中对记录进行分页处理
查看>>
数据库的应用详解三
查看>>
[翻译] 学习iOS开发的建议:如何从菜鸟到专家
查看>>
POJ 2376
查看>>
C++学习第二天(打卡)
查看>>
Java基础知识:Java实现Map集合二级联动3
查看>>
Teamwork(The sixth day of the team)
查看>>
(转)腾讯2011.10.15校园招聘会笔试题
查看>>
拉格朗日乘子法
查看>>