POJ 2114 - Boatherds
原题地址: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的更多相关文章
- poj 2114 Boatherds (树分治)
链接:http://poj.org/problem?id=2114 题意: 求树上距离为k的点对数量: 思路: 点分治.. 实现代码: #include<iostream> #includ ...
- POJ 2114 Boatherds 树分治
Boatherds Description Boatherds Inc. is a sailing company operating in the country of Trabantust ...
- POJ 2114 Boatherds【Tree,点分治】
求一棵树上是否存在路径长度为K的点对. POJ 1714求得是路径权值<=K的路径条数,这题只需要更改一下统计路径条数的函数即可,如果最终的路径条数大于零,则说明存在这样的路径. 刚开始我以为只 ...
- Poj 2114 Boatherds(点分治)
Boatherds Time Limit: 2000MS Memory Limit: 65536K Description Boatherds Inc. is a sailing company op ...
- poj 2114 Boatherds 树的分治
还是利用点的分治的办法来做,统计的办法不一样了,我的做法是排序并且标记每个点属于哪颗子树. #include <iostream> #include <cstdio> #inc ...
- POJ 2114 Boatherds 划分树
标题效果:鉴于一棵树,问有两点之间没有距离是k的. 数据的多组 思维:和IOI2011的Race喜欢.不是这么简单.阅读恶心,我是在主要功能的别人的在线副本. CODE: #include <c ...
- 树分治 点分治poj 2114
存在2点间距离==k 输出AYE 否则输出NAY #include<stdio.h> #include<string.h> #include<algorithm> ...
- poj 2114 树的分治 可作模板
/* 啊啊啊啊啊啊啊本题证明一个问题,在实际应用中sort比qsort块 还有memset这类初始化能不加尽量别加,很浪费时间 原来的程序把qsort该成sort,去掉一个无用memset就a了时间不 ...
- POJ 2114 点分治
思路: 点分治 //By SiriusRen #include <cstdio> #include <cstring> #include <algorithm> u ...
随机推荐
- Javascript引擎单线程机制及setTimeout执行原理说明
setTimeout用法在实际项目中还是会时常遇到.比如浏览器会聪明的等到一个函数堆栈结束后才改变DOM,如果再这个函数堆栈中把页面背景先从白色设为红色,再设回白色,那么浏览器会认为DOM没有发生任何 ...
- mybatis中:returned more than one row, where no more than one was expected.异常
org.mybatis.spring.MyBatisSystemException: nested exception is org.apache.ibatis.executor.ExecutorEx ...
- HDU3341 Lost's revenge(AC自动机&&dp)
一看到ACGT就会想起AC自动机上的dp,这种奇怪的联想可能是源于某道叫DNA什么的题的. 题意,给你很多个长度不大于10的小串,小串最多有50个,然后有一个长度<40的串,然后让你将这个这个长 ...
- Simulate a seven-sided die using only five-sided
问题描述: 如题 转述一下问题,就是说你现在有一个正五面体骰子,然后你怎么用这个正五面体骰子去模拟一个正七面体骰子. 这个问题我接触到几种方法,下面一一阐述. 方法一: rand7()=( rand5 ...
- 15条规则解析JavaScript对象布局(__proto__、prototype、constructor)
大家都说JavaScript的属性多,记不过来,各种结构复杂不易了解.确实JS是一门入门快提高难的语言,但是也有其他办法可以辅助记忆.下面就来讨论一下JS的一大难点-对象布局,究竟设计JS这门语言的人 ...
- 连接池和 "Timeout expired"异常
转自:博客园宁静.致远:http://www.cnblogs.com/zhangzhu/archive/2013/10/10/3361197.html 异常信息: MySql.Data.MySqlCl ...
- CVS的使用
基本术语 Repository 仓库 [rɪ'pɒzətrɪ] Module 模块 ['mɒdju:l] Import 导入 Checkout 导出 Commit 提交修改 [kə'mɪt] Upda ...
- module.xml 快捷代码
以下内容为淘宝装修模块描述文件(module.xml)快捷代码块,可以快速调整模块信息,详解请查阅>> http://open.taobao.com/doc/detail.htm?id=1 ...
- java基础篇---I/O技术
java基础篇---I/O技术 对于任何程序设计语言而言,输入输出(I/O)系统都是比较复杂的而且还是比较核心的.在java.io.包中提供了相关的API. java中流的概念划分 流的方向: 输 ...
- 脉络清晰的BP神经网络讲解,赞
学习是神经网络一种最重要也最令人注目的特点.在神经网络的发展进程中,学习算法的研究有着十分重要的地位.目前,人们所提出的神经网络模型都是和学习算 法相应的.所以,有时人们并不去祈求对模型和算法进行严格 ...