原题地址: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. 户外物理渗透:终端机,客户端的web测试思路

    现在的客户端界面越做越好看了,很多用到了web技术,轻便.界面炫.更新快,但是这样web的缺点也就出来了,就是不稳定,容易受用户等因素影响. 因为很多客户端web是内嵌的,内部通信,所以很多对安全的考 ...

  2. Pytho中两种方式导入模块的差别

    1.使用import module,只是把模块导入,访问模块中的函数名或者是属性是必须使用点运算符(.)来访问,否则直接访问会提示找不到这些函数或者属性. 2.使用from numpy import ...

  3. Nginx搭建flv视频点播服务器

    Nginx搭建flv视频点播服务器 前一段时间使用Nginx搭建的多媒体服务器只能在缓冲过的时间区域内拖放, 而不能拖放到未缓冲的地方. 这就带来了一个问题: 如果视频限速的速率很小, 那么客户端观看 ...

  4. Nagios 快速实现数据可视化的几种方式

    Nagios 是一款强大的开源监控软件,但他本身不能绘图,只能查看当前数据,不能看历史数据以及趋势,也正因此,想要更舒适的使用就要搭配绘图软件,现在可搭配的绘图软件有很多,例如 pnp4nagios, ...

  5. JQuery的ajax方法

    1.使用方式: 由于是全局方法,所以调用简单:$.ajax(); 2.可输入参数: 最好是写成一个json形式,个人不建议用链式,那样看上去不太好. 参数名称 类型 描述 dataType strin ...

  6. HDU 3518 Boring counting(后缀数组,字符处理)

    题目 参考自:http://blog.sina.com.cn/s/blog_64675f540100k9el.html 题目描述: 找出一个字符串中至少重复出现两次的字串的个数(重复出现时不能重叠). ...

  7. Razor视图引擎 语法学习(一)

    ASP.NET MVC是一种构建web应用程序的框架,它将一般的MVC(Model-View-Controller)模式应用于ASP.NET框架: ASP.NET约定优于配置:基本分为模型(对实体数据 ...

  8. Cpp多重继承会产生的问题

    多重继承常常被认为是 OOP 中一种复杂且不必要的部分.多重继承面临 crash 的场景并非难以想象,来看下面的例子. 1. 名称冲突 来看以下情况: 如果 Dog 类以及 Bird 类都有一个名为 ...

  9. BZOJ 1218: [HNOI2003]激光炸弹 前缀DP

    1218: [HNOI2003]激光炸弹 Description 一种新型的激光炸弹,可以摧毁一个边长为R的正方形内的所有的目标.现在地图上有n(N<=10000)个目标,用整数Xi,Yi(其值 ...

  10. 15.RDD 创建内幕解析

    第15课:RDD创建内幕 RDD的创建方式 Spark应用程序运行过程中,第一个RDD代表了Spark应用程序输入数据的来源,之后通过Trasformation来对RDD进行各种算子的转换,来实现具体 ...