[POJ1741] Tree【树分治 点分治】
传送门:http://poj.org/problem?id=1741
写的第一道树分治题,撒花纪念~
对于每一对点对(i, j),它有三种情况:
① 其中一个是根节点。这种情况比较简单,直接加上就好了。
② 横跨根节点。这种情况是重点。
③ 不是以上两种情况。这时递归下去求解就好了。
那么对于第二种情况该怎么破呢?设根节点为root,那么dist(i, root) + dist(j, root) <= k,且需要i与j在不同的子树里。直接算不同子树的点对(i, j)的个数会麻烦,所以需要一点技巧:符合条件且在不同子树的(i, j)的对数 = 符合条件的对数 - 符合条件且在相同子树的(i, j)的对数,这样就搞定啦!
- #include <cstdio>
- #include <cstring>
- #include <algorithm>
- const int maxn = 10005;
- int n, k, t1, t2, t3, ans;
- int head[maxn], to[maxn << 1], next[maxn << 1], w[maxn << 1], lb;
- int siz[maxn], a[maxn], left, right;
- bool book[maxn];
- inline void ist(int aa, int ss, int ww) {
- to[lb] = ss;
- next[lb] = head[aa];
- head[aa] = lb;
- w[lb] = ww;
- ++lb;
- }
- int fnd_zx(int fr, int tot_node, int p, int & rt, int & mn) {
- int mx = 0;
- for (int j = head[fr]; j != -1; j = next[j]) {
- if (!book[to[j]] && to[j] != p) {
- fnd_zx(to[j], tot_node, fr, rt, mn);
- mx = std::max(mx, siz[to[j]]);
- }
- }
- mx = std::max(mx, tot_node - siz[fr]);
- if (mn > mx) {
- mn = mx;
- rt = fr;
- }
- }
- void get_siz(int fr, int p) {
- siz[fr] = 1;
- for (int j = head[fr]; j != -1; j = next[j]) {
- if (!book[to[j]] && to[j] != p) {
- get_siz(to[j], fr);
- siz[fr] += siz[to[j]];
- }
- }
- }
- void get_data(int r, int p, int ww) {
- if (ww > k) {
- return;
- }
- a[right++] = ww;
- for (int j = head[r]; j != -1; j = next[j]) {
- if (!book[to[j]] && to[j] != p) {
- get_data(to[j], r, ww + w[j]);
- }
- }
- }
- int get_ans(int l, int r) {
- std::sort(a + l, a + r);
- int rt = 0;
- --r;
- while (r > l) {
- while (r > l && a[l] + a[r] > k) {
- --r;
- }
- rt += r - l;
- ++l;
- }
- return rt;
- }
- void slove(int fr) {
- int root = -666, mn = 2147483647;
- get_siz(fr, 0);
- fnd_zx(fr, siz[fr], 0, root, mn);
- book[root] = true;
- for (int j = head[root]; j != -1; j = next[j]) {
- if (!book[to[j]]) {
- slove(to[j]);
- }
- }
- left = right = 0;
- for (int j = head[root]; j != -1; j = next[j]) {
- if (!book[to[j]]) {
- get_data(to[j], root, w[j]);
- ans -= get_ans(left, right);
- left = right;
- }
- }
- ans += get_ans(0, right) + right;
- book[root] = false;
- }
- int main(void) {
- //freopen("in.txt", "r", stdin);
- while (scanf("%d%d", &n, &k) && n && k) {
- lb = 0;
- memset(head, -1, sizeof head);
- memset(next, -1, sizeof next);
- ans = 0;
- for (int i = 1; i < n; ++i) {
- scanf("%d%d%d", &t1, &t2, &t3);
- ist(t1, t2, t3);
- ist(t2, t1, t3);
- }
- slove(1);
- printf("%d\n", ans);
- }
- return 0;
- }
[POJ1741] Tree【树分治 点分治】的更多相关文章
- POJ1741——Tree(树的点分治)
1 /* *********************************************** 2 Author :kuangbin 3 Created Time :2013-11-17 1 ...
- 【poj1741】Tree 树的点分治
题目描述 Give a tree with n vertices,each edge has a length(positive integer less than 1001). Define dis ...
- hdu 4812 D Tree(树的点分治)
D Tree Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 102400/102400 K (Java/Others) Total ...
- [poj1741][tree] (树/点分治)
Description Give a tree with n vertices,each edge has a length(positive integer less than 1001). Def ...
- POJ1741 Tree 树分治模板
http://poj.org/problem?id=1741 题意:一棵n个点的树,每条边有距离v,求该树中距离小于等于k的点的对数. dis[y]表示点y到根x的距离,v代表根到子树根的距离 ...
- POJ1741(SummerTrainingDay08-G 树的点分治)
Tree Time Limit: 1000MS Memory Limit: 30000K Total Submissions: 23380 Accepted: 7748 Description ...
- hdu4812-D Tree (树的点分治)
昨天学了下树分治,今天补这道题,还是太不熟练了,写完之后一直超时.后来查出好多错= =比如v,u写倒了,比如+写成了取最值,比如....爆int...查了两个多小时的错..哭...(没想到进首页了 h ...
- 【POJ 1741】 Tree (树的点分治)
Tree Description Give a tree with n vertices,each edge has a length(positive integer less than 100 ...
- 树上点对统计poj1741(树的点分治)
给定一棵树,边上有权值,要统计有多少对点路径的权值和<=k 分治算法在树的路径中的应用 这个论文里面有分析. 任意两点的路径,要么过根结点,要么在子树中.如果在子树中,那么只要递归处理就行了. ...
- POJ 1741 Tree(树的点分治,入门题)
Tree Time Limit: 1000MS Memory Limit: 30000K Total Submissions: 21357 Accepted: 7006 Description ...
随机推荐
- win7右下角无线网图标显示未连接,但是实际上已连接上,也能上网
首先,要确实是不是服务启动的问题,方法很简单,重新启动电脑就可以. 如果问题依旧,那么按下Win+R快捷键,输入“services.msc”,打开服务界面. 然后会看到右侧窗口出现好多设置项,找到“R ...
- js 判断对象中所有属性是否为空
测试: var obj = {a:"123",b:""}; for(var key in obj){ if(!obj[key]) return; } 函数封装: ...
- 【Mongodb教程 第五课 】MongoDB 删除集合
drop() 方法 MongoDB 的 db.collection.drop() 是用来从数据库中删除一个集合. 语法: drop() 命令的基本语法如下 db.COLLECTION_NAME.dro ...
- 最简单实用的MongoDB安装教程:在CentOS中使用 yum 安装MongoDB及服务器端配置详解
一.准备工作: 运行yum命令查看MongoDB的包信息 [root@vm ~]# yum info mongo-10gen (提示没有相关匹配的信息,) 说明你的centos系统中的yum源不包含M ...
- wpf 导出Excel Wpf Button 样式 wpf简单进度条 List泛型集合对象排序 C#集合
wpf 导出Excel 1 private void Button_Click_1(object sender, RoutedEventArgs e) 2 { 3 4 ExportDataGrid ...
- 【Java报错】Message: 3 字节的 UTF-8 序列的字节 2 无效
报错logs 2015-03-10 10:15:32,360 ERROR [qtp32195030-27] [InvokeAfterValve.java:55] - javax.xml.stream. ...
- CentOS7.2 设置GRUB2引导界面分辨率
最近在学习OS引导启动,GRUB2的学习材料也不少,主要还看官方手册清晰些. 公司里办公机的多启动用的ubuntu的界面,还挺炫酷的.之前看其他博客网文里看到可以设置grub2的分辨率,我拿CentO ...
- Java String 和 new String()的区别
Java String 和 new String()的区别 本文转自:http://www.cnblogs.com/heima-jieqi/archive/2012/04/10/2440086.htm ...
- [学习笔记]dsu on a tree(如何远离线段树合并)
https://www.zybuluo.com/ysner/note/1318613 背景 这玩意来源于一种有局限性的算法. 有一种广为人知的,树上离线维护子树信息的做法. (可以参照luogu360 ...
- bzoj 2006 超级钢琴 —— ST表
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2006 本来应该是可以用主席树,找区间最小值,取出来后再找那段区间的次小值...... 但也可 ...