原题地址: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. RVA与Offset的换算函数

    function RVAToFileOffset(FileName:string; RVA: Cardinal): Cardinal; var   MemPE: TFileStream;   PEDo ...

  2. UML组件图(转载)

    概述: 组件图是不同的性质和行为.组件图用于模拟物理方面的系统. 现在的问题是什么,这些物理方面?物理方面的元素,如可执行文件,库,文件,证件等它位于在一个节点. 因此,组件图用于可视化的组织和系统组 ...

  3. Kerberos的组件和术语(翻译和注解)

    之所以要翻译这篇文章,是因为提到了一些通常于对Kerberos协议简介性质的文章所没有提到的细节,而这些细节对于理解Kerberos的工作原理,以及Kerberos协议实现的使用都是很有必要的. 1. ...

  4. Android 添加Button事件

    protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentV ...

  5. Razor语法学习

    原文:http://www.cnblogs.com/youring2/archive/2011/07/24/2115254.html 1.Razor的文件类型 Razor支持两种文件类型,分别是.cs ...

  6. CRF++中文分词使用指南

    http://blog.csdn.net/marising/article/details/5769653 前段时间写了中文分词的一些记录里面提到了CRF的分词方法,近段时间又研究了一下,特把方法写下 ...

  7. codeforces 425B Sereja and Table(状态压缩,也可以数组模拟)

    题目 给出一个n*m的01矩阵, 让你最多改变k个里面的值(0变1,1变0), 使得0.1的连通分量是矩阵.输出最少步数 1 ≤ n, m ≤ 100; 1 ≤ k ≤ 10 题解: 如果01连通分量 ...

  8. cf 403 D

    D. Beautiful Pairs of Numbers time limit per test 3 seconds memory limit per test 256 megabytes inpu ...

  9. POJ 3696 The Luckiest number (欧拉函数,好题)

    该题没思路,参考了网上各种题解.... 注意到凡是那种11111..... 22222..... 33333.....之类的序列都可用这个式子来表示:k*(10^x-1)/9进而简化:8 * (10^ ...

  10. 构建iOS稳定应用架构时方案选择的思考,主要涉及工程结构,数据流思想和代码规范

    工程结构架构,减少耦合混乱以及防治需求大改造成结构重构,如何构建稳定可扩展可变换的工程结构的思考 我打算采用Information flow的方式自上而下,两大层分为基础层和展现层的结构.基础层分为多 ...