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 ...
随机推荐
- WPF编程学习——布局
本文目录 1.布局简介 2.面板(Panel) 3.视图框(Viewbox) 4.滚动视图控件(ScrollViewer) 5.公共布局属性 1.布局简介 应用程序界面设计中,合理的元素布局至关重要, ...
- sublime text3 插件安装
安装Package control 先打开安装代码的命令行 按 ctrl+~或者 view -> show console 将下面的代码粘贴到输入框里 按回车 import urllib.re ...
- ssh 远程 centos 乱码
今天,帮我们同学处理一下中文显示乱码的问题.这个是个国内Linux用户烦恼的问题,由于大部分的Linux发行版都是以英语为主体的,而且英文在通用性和稳定性上都比中文要好一些,各种奇怪的BUG也要少一点 ...
- 开源搜索引擎Solr的快速搭建及集成到企业门户最佳实施方案--转载
笔者经过研究查阅solr官方相关资料经过两周的研究实现了毫秒级百万数据的搜索引擎的搭建并引入到企业门户.现将实施心得和步骤分享一下. 1. jdk1.6 安装jdk1.6到系统默认目录下X: ...
- 转:jxl导出excel(合并单元格)
Demo 代码如下: import java.io.*; import jxl.*; import jxl.format.UnderlineStyle; import jxl.write.*; pub ...
- HBase保存的各个字段意义解释
/×××××××××××××××××××××××××××××××××××××××××/ Author:xxx0624 HomePage:http://www.cnblogs.com/xxx0624/ ...
- poj 1733(带权并查集+离散化)
题目链接:http://poj.org/problem?id=1733 思路:这题一看就想到要用并查集做了,不过一看数据这么大,感觉有点棘手,其实,我们仔细一想可以发现,我们需要记录的是出现过的节点到 ...
- Ajax的进阶学习(一)
在Ajax课程中,我们了解了最基本的异步处理方式.本章,我们将了解一下Ajax的一些全局请求事件.跨域处理和其他一些问题. 加载请求 在Ajax异步发送请求时,遇到网速较慢的情况,就会出现请求时间较长 ...
- Java:内部类
1.内部类的定义: 一个内部类可以定义在另一个类里,可以定义在函数里,甚至可以作为一个表达式的一部分. 2.内部类的分类: Java中的内部类共分为四种: 成员内部类member inner clas ...
- 客户端用httpurlconnection来进行http连接的
客户端用httpurlconnection来进行http连接的,并设置restful风格 请求响应流程 设置连接参数的方法 setAllowUserInteraction setDoInput set ...