原题地址:http://poj.org/problem?id=2114

题目大意:

给定一棵点数为\(n~(n \le 10000)\)的无根树,路径上有权值,给出m组询问($m \le 100$),每组询问给出一个k,问树中是否存在长度为k的链。题目是多case

题目分析:

这是第二次写树分治,细节想清楚真的很重要啊。。。写了两天才写过,接下来说一说算法流程和需要注意的细节吧

首先读入、建图等等等等。。

然后是分治过程:

0.如果当前处理的这棵树的size很小了,调用暴力解决,否则继续执行(这相当于边界处理)

1.找出当前要处理的树的重心作为分治点

2.算出重心到这棵树中每个点的距离,扫出来是否有两个点的距离和等于要询问的值,有则加上对数

3.将重心发出的所有边断开,计算每棵子树中到重心距离和为k的点对,在答案中减去

4.递归处理所有子树,根据最终得到的个数判断是否存在

分治过程看起来很简单,但是有几个细节需要注意:断边的时候断开邻接表需要小心。每一次递归我们都需要初始化一些变量,但是每次全部初始化的代价过于高昂,而且会影响到当前树中没有的节点,每次初始化都BFS一遍过于麻烦,所有可以开若干个vector表示当前递归处理的子树中的点,然后就可以减少复杂度。计算距离之后需要排序去重以便高效地计算出要求的值。

(准备省选过于忙碌了一直没来得及写什么总结……学了不少新知识回头都得抓紧总结了)

 //date 20140417
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector> const int maxn = ;
const int INF = 0x7FFFFFFF;
const int r1 = ; using namespace std;
typedef vector<int> array;
typedef array::iterator iter;
typedef vector<array>::iterator viter; inline int getint()
{
int ans(); char w = getchar();
while(w < '' || '' < w)w = getchar();
while('' <= w && w <= '')
{
ans = ans * + w - '';
w = getchar();
}
return ans;
} inline int innew(int &a, int b){if(a < b){a = b; return ;}return ;}
inline int denew(int &a, int b){if(a > b){a = b; return ;}return ;} struct edge
{
int v, w, next;
}E[maxn << ];
int a[maxn], nedge;
int n;
int ask[maxn], ans[maxn], nsk; vector<array> P;
array tmp; inline void add(int u, int v, int w)
{
E[++nedge].v = v;
E[nedge].w = w;
E[nedge].next = a[u];
a[u] = nedge;
} namespace d_c
{
int yff, dis[maxn], list[maxn], size[maxn], p[maxn];
int q[maxn], st, ed;
int d[maxn], last, now[maxn], had[maxn];
int tlist[maxn], ttot, plist[maxn]; inline int getcend(int k, int yff)
{
for(iter i = P[k].begin(); i != P[k].end(); ++i)
{
size[*i] = p[*i] = ; now[*i] = a[*i];
}
size[d[last = ] = P[k][]] = ;
while(last)
{
int i = d[last], j = now[i];
if(!j)
{
if(--last) size[d[last]] += size[i];
continue;
}
if(!size[E[j].v])
{
size[d[++last] = E[j].v] = ;
p[E[j].v] = i;
}
now[i] = E[j].next;
}
int Max, ans, Min = INF;
for(iter i = P[k].begin(); i != P[k].end(); ++i)
{
Max = yff - size[*i];
for(int j = a[*i]; j; j = E[j].next)if(p[*i] != E[j].v)
innew(Max, size[E[j].v]);
if(denew(Min, Max))ans = *i;
}
if(p[ans])size[p[ans]] = yff - size[ans];
return ans;
} inline void brutf(int k, int yff)
{
for(iter i = P[k].begin(); i != P[k].end(); ++i)
{
for(iter j = P[k].begin(); j != P[k].end(); ++j)dis[*j] = list[*j] = ;
int st = , ed = , tot;
q[dis[*i] = ] = *i;
while(st < ed)
{
int x = q[++st];
for(int i = a[x]; i; i = E[i].next)if(!dis[E[i].v])
dis[q[++ed] = E[i].v] = dis[x] + E[i].w;
}
for(iter j = P[k].begin(); j != P[k].end(); ++j)
for(int need = ; need <= nsk; ++need)
ans[need] += (dis[*j] == ask[need] + ) << ;
}
} inline void main(int k)
{
yff = P[k].size();
if(yff <= r1){brutf(k, yff); return;}
int cend = getcend(k, yff);
for(iter i = P[k].begin(); i != P[k].end(); ++i) dis[*i] = had[*i] = ;
st = ; ed = ; int tot;
list[dis[q[] = cend] = tot = ] = ;
while(st < ed)
{
int x = q[++st];
for(int i = a[x]; i; i = E[i].next)if(!dis[E[i].v])
{
list[++tot] = dis[q[++ed] = E[i].v] = dis[x] + E[i].w;
}
} sort(list + , list + tot + );
tlist[plist[] = ttot = ] = list[];
for(int i = ; i <= tot; ++i)
{
if(list[i] == list[i - ])++plist[ttot];
else {tlist[++ttot] = list[i]; plist[ttot] = ;}
} for(int need = ; need <= nsk; ++need)
{
int j = ttot;
for(int i = ; i <= ttot; ++i)
{
while(j && (tlist[j] + tlist[i] > ask[need] + ))--j;
if(!j)break;
if(tlist[j] + tlist[i] == ask[need] + )
{
if(j != i)ans[need] += plist[i] * plist[j];
else ans[need] += plist[i] * (plist[i] - );
}
}
} for(int i = a[cend]; i; i = E[i].next)
{
int sign = ;
if(a[E[i].v] == (i ^ )){a[E[i].v] = E[i ^ ].next;}
else
{
int last;
for(int j = a[E[i].v]; j != (i ^ ); j = E[j].next) last = j;
E[last].next = E[i ^ ].next;
}
tmp.clear();
st = ; ed = ; q[had[E[i].v] = ] = E[i].v;
tmp.push_back(E[i].v);
list[tot = ] = dis[E[i].v];
while(st < ed)
{
int x = q[++st];
for(int j = a[x]; j; j = E[j].next)
if(!had[E[j].v]){tmp.push_back(E[j].v); had[E[j].v] = ; q[++ed] = E[j].v; list[++tot] = dis[E[j].v];}
}
sort(list + , list + tot + );
tlist[plist[] = ttot = ] = list[];
for(int w = ; w <= tot; ++w)
{
if(list[w] == list[w - ])++plist[ttot];
else {tlist[++ttot] = list[w]; plist[ttot] = ;}
} for(int need = ; need <= nsk; ++need)
{
int j = ttot;
for(int w = ; w <= ttot; ++w)
{
while(j && (tlist[j] + tlist[w] > ask[need] + ))--j;
if(!j)break;
if(tlist[w] + tlist[j] == ask[need] + )
{
if(j != w)ans[need] -= plist[w] * plist[j];
else ans[need] -= plist[w] * (plist[w] - );
}
}
} P.push_back(tmp);
main(P.size() - );
} }
} int main()
{
while(true)
{
n = getint();
if(!n)break;
P.clear(); tmp.clear();
memset(a, , sizeof a);
memset(ans, , sizeof ans);
nedge = ; for(int i = ; i <= n; ++i)tmp.push_back(i);
P.push_back(tmp); for(int i = ; i <= n; ++i)
{
int x, w;
while(true)
{
x = getint();
if(!x)break;
w = getint();
add(i, x, w); add(x, i, w);
}
}
nsk = ;
while(true)
{
ask[++nsk] = getint();
if(!ask[nsk]){--nsk; break;}
}
d_c::main();
for(int i = ; i <= nsk; ++i)printf("%s\n", ans[i] > ? "AYE" : "NAY");
printf(".\n");
} return ;
}

POJ 2114 - Boatherds的更多相关文章

  1. poj 2114 Boatherds (树分治)

    链接:http://poj.org/problem?id=2114 题意: 求树上距离为k的点对数量: 思路: 点分治.. 实现代码: #include<iostream> #includ ...

  2. POJ 2114 Boatherds 树分治

    Boatherds     Description Boatherds Inc. is a sailing company operating in the country of Trabantust ...

  3. POJ 2114 Boatherds【Tree,点分治】

    求一棵树上是否存在路径长度为K的点对. POJ 1714求得是路径权值<=K的路径条数,这题只需要更改一下统计路径条数的函数即可,如果最终的路径条数大于零,则说明存在这样的路径. 刚开始我以为只 ...

  4. Poj 2114 Boatherds(点分治)

    Boatherds Time Limit: 2000MS Memory Limit: 65536K Description Boatherds Inc. is a sailing company op ...

  5. poj 2114 Boatherds 树的分治

    还是利用点的分治的办法来做,统计的办法不一样了,我的做法是排序并且标记每个点属于哪颗子树. #include <iostream> #include <cstdio> #inc ...

  6. POJ 2114 Boatherds 划分树

    标题效果:鉴于一棵树,问有两点之间没有距离是k的. 数据的多组 思维:和IOI2011的Race喜欢.不是这么简单.阅读恶心,我是在主要功能的别人的在线副本. CODE: #include <c ...

  7. 树分治 点分治poj 2114

    存在2点间距离==k 输出AYE 否则输出NAY #include<stdio.h> #include<string.h> #include<algorithm> ...

  8. poj 2114 树的分治 可作模板

    /* 啊啊啊啊啊啊啊本题证明一个问题,在实际应用中sort比qsort块 还有memset这类初始化能不加尽量别加,很浪费时间 原来的程序把qsort该成sort,去掉一个无用memset就a了时间不 ...

  9. POJ 2114 点分治

    思路: 点分治 //By SiriusRen #include <cstdio> #include <cstring> #include <algorithm> u ...

随机推荐

  1. 引擎设计跟踪(九.9) 文件包系统(Game Package System)

    很早之前,闪现过写文件包系统的想法, 但是觉得还没有到时候. 由于目前工作上在做android ndk开发, 所以业余时间趁热做了android的移植, 因为android ndk提供的mountab ...

  2. JavaScript之With语句讲解

    有了With 语句,在存取对象属性和方法时就不用重复指定参考对象,在 With 语句块中,凡是 JavaScript 不识别的属性和方法都和该语句块指定的对象有关.With 语句的语法格式如下所示:W ...

  3. jQuery实现 浏览器后退到上次浏览位置

    近日看腾讯.新浪的移动端网站,发现一件非常蛋疼的事情,在列表浏览内容,我往下翻,往下翻,突然,看到一个十分霸气的标题,于是点到文章查看详细内容,若干时间后,点回退按钮,浏览器回退到页面的最顶部了. 于 ...

  4. NtpClient

    http://www.baidu.com/link?url=IWGCXsX4Mns_ZjEF6HYEK156xCsndi9Bu1w3x_YiaJfdsr8vf0Q5worm43W3OiEmSHpzTp ...

  5. C/C++ 位域知识小结

    C/C++ 位域知识小结 几篇较全面的位域相关的文章: http://www.uplook.cn/blog/9/93362/ C/C++位域(Bit-fields)之我见 C中的位域与大小端问题 内存 ...

  6. 快速构建自己的CentOS发行版

    一.制作LTOS具体过程 光盘结构介绍 * isolinux 目录存放光盘启动时的安装界面信息 * images 目录包括了必要的启动映像文件 * CentOS 目录存放安装软件包及信息 * .dis ...

  7. 模拟登陆115网盘(MFC版)

    [cpp] view plain copy // 模拟登陆115网盘 #include <afxinet.h> // 包含相关的头文件 /* 用抓包工具抓包可得到需要提交的数据,然后模拟提 ...

  8. JavaWeb笔记——三大组件之监听器

    1 JavaWeb监听器概述 在JavaWeb被监听的事件源为:ServletContext.HttpSession.ServletRequest,即三大域对象. l  监听域对象“创建”与“销毁”的 ...

  9. MySql存储引擎特性对比

    下表显示了各种存储引擎的特性: 其中最常见的两种存储引擎是MyISAM和InnoDB 刚接触MySQL的时候可能会有些惊讶,竟然有不支持事务的存储引擎,学过关系型数据库理论的人都知道,事务是关系型数据 ...

  10. 276. Paint Fence

    题目: There is a fence with n posts, each post can be painted with one of the k colors. You have to pa ...